OLD | NEW |
---|---|
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 4233 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
4244 new_offset); | 4244 new_offset); |
4245 if (!result) return false; | 4245 if (!result) return false; |
4246 lower_check_->ReplaceAllUsesWith(lower_check_->index()); | 4246 lower_check_->ReplaceAllUsesWith(lower_check_->index()); |
4247 lower_check_->SetOperandAt(0, added_lower_index_); | 4247 lower_check_->SetOperandAt(0, added_lower_index_); |
4248 } | 4248 } |
4249 } else { | 4249 } else { |
4250 ASSERT(false); | 4250 ASSERT(false); |
4251 } | 4251 } |
4252 | 4252 |
4253 if (!keep_new_check) { | 4253 if (!keep_new_check) { |
4254 BasicBlock()->graph()->isolate()->counters()-> | |
4255 bounds_checks_covered()->Increment(); | |
4254 new_check->DeleteAndReplaceWith(new_check->ActualValue()); | 4256 new_check->DeleteAndReplaceWith(new_check->ActualValue()); |
4255 } | 4257 } |
4256 | 4258 |
4257 return true; | 4259 return true; |
4258 } | 4260 } |
4259 | 4261 |
4260 void RemoveZeroOperations() { | 4262 void RemoveZeroOperations() { |
4261 RemoveZeroAdd(&added_lower_index_, &added_lower_offset_); | 4263 RemoveZeroAdd(&added_lower_index_, &added_lower_offset_); |
4262 RemoveZeroAdd(&added_upper_index_, &added_upper_offset_); | 4264 RemoveZeroAdd(&added_upper_index_, &added_upper_offset_); |
4263 } | 4265 } |
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
4366 void Delete(BoundsCheckKey* key) { | 4368 void Delete(BoundsCheckKey* key) { |
4367 Remove(key, key->Hash()); | 4369 Remove(key, key->Hash()); |
4368 } | 4370 } |
4369 | 4371 |
4370 explicit BoundsCheckTable(Zone* zone) | 4372 explicit BoundsCheckTable(Zone* zone) |
4371 : ZoneHashMap(BoundsCheckKeyMatch, ZoneHashMap::kDefaultHashMapCapacity, | 4373 : ZoneHashMap(BoundsCheckKeyMatch, ZoneHashMap::kDefaultHashMapCapacity, |
4372 ZoneAllocationPolicy(zone)) { } | 4374 ZoneAllocationPolicy(zone)) { } |
4373 }; | 4375 }; |
4374 | 4376 |
4375 | 4377 |
4378 class InductionVariableBlocksTable BASE_EMBEDDED { | |
titzer
2013/06/24 14:03:30
Highly recommend moving this class and related fun
Massi
2013/07/01 13:10:49
Done.
| |
4379 public: | |
4380 class Element { | |
4381 public: | |
4382 static const int kNoBlock = -1; | |
4383 | |
4384 HBasicBlock* block() { return block_; } | |
4385 void set_block(HBasicBlock* block) { block_ = block; } | |
4386 int current_successor() { return current_successor_; } | |
4387 int backtrack_to() { return backtrack_to_; } | |
4388 bool is_start() { return is_start_; } | |
4389 bool is_proper_exit() { return is_proper_exit_; } | |
4390 bool is_in_loop() { return is_in_loop_; } | |
4391 bool has_check() { return has_check_; } | |
4392 void set_has_check() { has_check_ = true; } | |
4393 InductionVariableLimitUpdate* additional_limit() { | |
4394 return &additional_limit_; | |
4395 } | |
4396 | |
4397 void InitializeLoop(InductionVariableData* data) { | |
4398 ASSERT(data->limit() != NULL); | |
4399 HLoopInformation* loop = data->phi()->block()->current_loop(); | |
4400 current_successor_ = kNoBlock; | |
4401 backtrack_to_ = kNoBlock; | |
4402 is_start_ = (block() == loop->loop_header()); | |
4403 is_proper_exit_ = (block() == data->induction_exit_target()); | |
4404 is_in_loop_ = loop->IsNestedInThisLoop(block()); | |
4405 has_check_ = false; | |
4406 } | |
4407 | |
4408 void ClearIterationData() { | |
4409 current_successor_ = kNoBlock; | |
4410 backtrack_to_ = kNoBlock; | |
4411 } | |
4412 | |
4413 int CurrentSuccessorBlock() { | |
4414 if (current_successor_ < block()->end()->SuccessorCount()) { | |
4415 return block()->end()->SuccessorAt(current_successor_)->block_id(); | |
4416 } else { | |
4417 return kNoBlock; | |
4418 } | |
4419 } | |
4420 | |
4421 int PerformStep(int from_block, bool* failure, bool* unsafe) { | |
4422 if (!is_in_loop()) { | |
4423 if (!is_proper_exit()) { | |
4424 *unsafe = true; | |
4425 } | |
4426 return from_block; | |
4427 } | |
4428 | |
4429 if (is_start() && | |
4430 from_block != kNoBlock && | |
4431 from_block != CurrentSuccessorBlock()) { | |
4432 *failure = true; | |
4433 return from_block; | |
4434 } | |
4435 | |
4436 if (has_check()) { | |
4437 return from_block; | |
4438 } | |
4439 | |
4440 if (current_successor_ == kNoBlock) { | |
4441 backtrack_to_ = from_block; | |
4442 } | |
4443 current_successor_++; | |
4444 | |
4445 if (CurrentSuccessorBlock() != kNoBlock) { | |
4446 return CurrentSuccessorBlock(); | |
4447 } else { | |
4448 return backtrack_to(); | |
4449 } | |
4450 } | |
4451 | |
4452 Element() | |
4453 : block_(NULL), current_successor_(kNoBlock), backtrack_to_(kNoBlock), | |
4454 is_start_(false), is_proper_exit_(false), has_check_(false), | |
4455 additional_limit_() {} | |
4456 | |
4457 private: | |
4458 HBasicBlock* block_; | |
4459 int current_successor_; | |
4460 int backtrack_to_; | |
4461 bool is_start_; | |
4462 bool is_proper_exit_; | |
4463 bool is_in_loop_; | |
4464 bool has_check_; | |
4465 InductionVariableLimitUpdate additional_limit_; | |
4466 }; | |
4467 | |
4468 HGraph* graph() { return graph_; } | |
4469 HBasicBlock* loop_header() { return loop_header_; } | |
4470 Element* at(int index) { return &(elements_.at(index)); } | |
4471 Element* at(HBasicBlock* block) { return at(block->block_id()); } | |
4472 | |
4473 void add_check_at(int index) { | |
4474 at(index)->set_has_check(); | |
4475 } | |
4476 void add_check_at(HBasicBlock* block) { | |
4477 add_check_at(block->block_id()); | |
4478 } | |
4479 | |
4480 void InitializeLoop(InductionVariableData* data) { | |
4481 for (int i = 0; i < graph()->blocks()->length(); i++) { | |
4482 at(i)->InitializeLoop(data); | |
4483 } | |
4484 loop_header_ = data->phi()->block()->current_loop()->loop_header(); | |
4485 } | |
4486 | |
4487 void ClearIterationData() { | |
4488 ASSERT(loop_header() != NULL); | |
4489 HLoopInformation* loop = loop_header()->loop_information(); | |
4490 for (int i = 0; i < loop->blocks()->length(); i++) { | |
4491 at(loop->blocks()->at(i)->block_id())->ClearIterationData(); | |
4492 } | |
4493 } | |
4494 | |
4495 bool LoopPathsAreChecked(bool* unsafe) { | |
4496 bool failure = false; | |
4497 *unsafe = false; | |
4498 int previous_block = Element::kNoBlock; | |
4499 int current_block = loop_header()->block_id(); | |
4500 while (current_block != Element::kNoBlock) { | |
4501 int next_block = at(current_block)->PerformStep(previous_block, | |
4502 &failure, unsafe); | |
4503 previous_block = current_block; | |
4504 current_block = next_block; | |
4505 if (failure) return false; | |
4506 } | |
4507 return true; | |
4508 } | |
4509 | |
4510 void AddCheck(HBoundsCheck* check) { | |
4511 at(check->block()->block_id())->set_has_check(); | |
4512 } | |
4513 | |
4514 explicit InductionVariableBlocksTable(HGraph* graph) | |
4515 : graph_(graph), loop_header_(NULL), | |
4516 elements_(graph->blocks()->length(), graph->zone()) { | |
4517 for (int i = 0; i < graph->blocks()->length(); i++) { | |
4518 Element element; | |
4519 element.set_block(graph->blocks()->at(i)); | |
4520 elements_.Add(element, graph->zone()); | |
4521 ASSERT(at(i)->block()->block_id() == i); | |
4522 } | |
4523 } | |
4524 | |
4525 void ProcessRelatedChecks( | |
4526 InductionVariableData::InductionVariableCheck* check, | |
4527 InductionVariableData* data) { | |
4528 HValue* length = check->check()->length(); | |
4529 ClearIterationData(); | |
4530 check->set_processed(); | |
4531 HBasicBlock* header = | |
4532 data->phi()->block()->current_loop()->loop_header(); | |
4533 HBasicBlock* pre_header = header->predecessors()->at(0); | |
4534 if (!data->limit()->IsInteger32Constant()) { | |
4535 HBasicBlock* limit_block = data->limit()->block(); | |
4536 if (limit_block != pre_header && | |
4537 !limit_block->Dominates(pre_header)) { | |
4538 return; | |
4539 } | |
4540 } | |
4541 if (!(data->limit()->representation().Equals( | |
4542 length->representation()) || | |
4543 data->limit()->IsInteger32Constant())) { | |
4544 return; | |
4545 } | |
4546 if (check->check()->length()->block() != pre_header && | |
4547 !check->check()->length()->block()->Dominates(pre_header)) { | |
4548 return; | |
4549 } | |
4550 | |
4551 for (InductionVariableData::InductionVariableCheck* current_check = check; | |
4552 current_check != NULL; | |
4553 current_check = current_check->next()) { | |
4554 if (current_check->check()->length() != length) continue; | |
4555 | |
4556 add_check_at(current_check->check()->block()); | |
4557 current_check->set_processed(); | |
4558 } | |
4559 | |
4560 bool unsafe; | |
4561 bool failure = !LoopPathsAreChecked(&unsafe); | |
4562 | |
4563 if (failure || (unsafe && !graph()->use_optimistic_licm())) { | |
4564 return; | |
4565 } | |
4566 | |
4567 bool has_upper_constant_limit = true; | |
4568 InductionVariableData::InductionVariableCheck* current_check = check; | |
4569 int32_t upper_constant_limit = | |
4570 current_check != NULL && current_check->HasUpperLimit() ? | |
4571 current_check->upper_limit() : 0; | |
4572 while (current_check != NULL) { | |
4573 if (check->HasUpperLimit()) { | |
4574 if (check->upper_limit() != upper_constant_limit) { | |
4575 has_upper_constant_limit = false; | |
4576 } | |
4577 } else { | |
4578 has_upper_constant_limit = false; | |
4579 } | |
4580 | |
4581 current_check->check()->set_skip_check(); | |
4582 current_check = current_check->next(); | |
4583 } | |
4584 | |
4585 HValue* limit = data->limit(); | |
4586 | |
4587 if (has_upper_constant_limit) { | |
4588 HConstant* new_limit = new(pre_header->graph()->zone()) HConstant( | |
4589 upper_constant_limit, length->representation()); | |
4590 new_limit->InsertBefore(pre_header->end()); | |
4591 limit = new_limit; | |
4592 } | |
4593 if (limit->IsInteger32Constant() && | |
4594 limit->block() != pre_header && | |
4595 !limit->block()->Dominates(pre_header)) { | |
4596 HConstant* new_limit = new(pre_header->graph()->zone()) HConstant( | |
4597 limit->GetInteger32Constant(), length->representation()); | |
4598 new_limit->InsertBefore(pre_header->end()); | |
4599 limit = new_limit; | |
4600 } | |
4601 HBoundsCheck* hoisted_check = new(pre_header->zone()) HBoundsCheck( | |
4602 limit, check->check()->length()); | |
4603 hoisted_check->InsertBefore(pre_header->end()); | |
4604 hoisted_check->set_allow_equality(true); | |
4605 } | |
4606 | |
4607 private: | |
4608 HGraph* graph_; | |
4609 HBasicBlock* loop_header_; | |
4610 ZoneList<Element> elements_; | |
4611 }; | |
4612 | |
4613 | |
4614 void HGraph::CollectInductionVariableData( | |
4615 HBasicBlock* bb, | |
4616 InductionVariableBlocksTable* table) { | |
4617 bool additional_limit = false; | |
4618 | |
4619 for (int i = 0; i < bb->phis()->length(); i++) { | |
4620 HPhi* phi = bb->phis()->at(i); | |
4621 phi->DetectInductionVariable(); | |
4622 } | |
4623 | |
4624 additional_limit = InductionVariableData::ComputeInductionVariableLimit( | |
4625 bb, table->at(bb)->additional_limit()); | |
4626 | |
4627 if (additional_limit) { | |
4628 table->at(bb)->additional_limit()->updated_variable-> | |
4629 UpdateAdditionalLimit(table->at(bb)->additional_limit()); | |
4630 } | |
4631 | |
4632 for (HInstruction* i = bb->first(); i != NULL; i = i->next()) { | |
4633 if (!i->IsBoundsCheck()) continue; | |
4634 HBoundsCheck* check = HBoundsCheck::cast(i); | |
4635 int32_t and_mask; | |
4636 int32_t or_mask; | |
4637 HValue* context; | |
4638 HValue* base_index = InductionVariableData::DecomposeBitwise( | |
4639 check->index(), &and_mask, &or_mask, &context); | |
4640 if (!base_index->IsPhi()) continue; | |
4641 HPhi* phi = HPhi::cast(base_index); | |
4642 | |
4643 if (!phi->IsInductionVariable()) continue; | |
4644 InductionVariableData* data = phi->induction_variable_data(); | |
4645 | |
4646 // For now ignore loops decrementing the index. | |
4647 if (data->increment() <= 0) continue; | |
4648 if (!data->lower_limit_is_non_negative_constant()) continue; | |
4649 | |
4650 // TODO(mmassi): skip OSR values for check->length(). | |
4651 if (check->length() == data->limit() || | |
4652 check->length() == data->additional_upper_limit()) { | |
4653 check->set_skip_check(); | |
4654 continue; | |
4655 } | |
4656 | |
4657 if (!phi->IsLimitedInductionVariable()) continue; | |
4658 | |
4659 int32_t limit = data->ComputeUpperLimit(and_mask, or_mask); | |
4660 phi->induction_variable_data()->AddCheck(check, limit); | |
4661 } | |
4662 | |
4663 for (int i = 0; i < bb->dominated_blocks()->length(); i++) { | |
4664 CollectInductionVariableData(bb->dominated_blocks()->at(i), table); | |
4665 } | |
4666 | |
4667 if (additional_limit) { | |
4668 table->at(bb->block_id())->additional_limit()->updated_variable-> | |
4669 UpdateAdditionalLimit(table->at(bb->block_id())->additional_limit()); | |
4670 } | |
4671 } | |
4672 | |
4673 | |
4674 void HGraph::EliminateRedundantBoundsChecksUsingInductionVariables( | |
4675 HBasicBlock* bb, | |
4676 InductionVariableBlocksTable* table) { | |
4677 for (int i = 0; i < bb->phis()->length(); i++) { | |
4678 HPhi* phi = bb->phis()->at(i); | |
4679 if (!phi->IsLimitedInductionVariable()) continue; | |
4680 | |
4681 InductionVariableData* induction_data = phi->induction_variable_data(); | |
4682 InductionVariableData::ChecksRelatedToLength* current_length_group = | |
4683 induction_data->checks(); | |
4684 while (current_length_group != NULL) { | |
4685 current_length_group->CloseCurrentBlock(); | |
4686 InductionVariableData::InductionVariableCheck* current_base_check = | |
4687 current_length_group->checks(); | |
4688 table->InitializeLoop(induction_data); | |
4689 | |
4690 while (current_base_check != NULL) { | |
4691 table->ProcessRelatedChecks(current_base_check, induction_data); | |
4692 while (current_base_check != NULL && current_base_check->processed()) { | |
4693 current_base_check = current_base_check->next(); | |
4694 } | |
4695 } | |
4696 | |
4697 current_length_group = current_length_group->next(); | |
4698 } | |
4699 } | |
4700 } | |
4701 | |
4702 | |
4703 void HGraph::EliminateRedundantBoundsChecksUsingInductionVariables() { | |
4704 InductionVariableBlocksTable table(this); | |
4705 CollectInductionVariableData(entry_block(), &table); | |
4706 for (int i = 0; i < blocks()->length(); i++) { | |
4707 EliminateRedundantBoundsChecksUsingInductionVariables(blocks()->at(i), | |
4708 &table); | |
4709 } | |
4710 } | |
4711 | |
4712 | |
4376 // Eliminates checks in bb and recursively in the dominated blocks. | 4713 // Eliminates checks in bb and recursively in the dominated blocks. |
4377 // Also replace the results of check instructions with the original value, if | 4714 // Also replace the results of check instructions with the original value, if |
4378 // the result is used. This is safe now, since we don't do code motion after | 4715 // the result is used. This is safe now, since we don't do code motion after |
4379 // this point. It enables better register allocation since the value produced | 4716 // this point. It enables better register allocation since the value produced |
4380 // by check instructions is really a copy of the original value. | 4717 // by check instructions is really a copy of the original value. |
4381 void HGraph::EliminateRedundantBoundsChecks(HBasicBlock* bb, | 4718 void HGraph::EliminateRedundantBoundsChecks(HBasicBlock* bb, |
4382 BoundsCheckTable* table) { | 4719 BoundsCheckTable* table) { |
4383 BoundsCheckBbData* bb_data_list = NULL; | 4720 BoundsCheckBbData* bb_data_list = NULL; |
4384 | 4721 |
4385 for (HInstruction* i = bb->first(); i != NULL; i = i->next()) { | 4722 for (HInstruction* i = bb->first(); i != NULL; i = i->next()) { |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
4441 table->Delete(data->Key()); | 4778 table->Delete(data->Key()); |
4442 } | 4779 } |
4443 } | 4780 } |
4444 } | 4781 } |
4445 | 4782 |
4446 | 4783 |
4447 void HGraph::EliminateRedundantBoundsChecks() { | 4784 void HGraph::EliminateRedundantBoundsChecks() { |
4448 HPhase phase("H_Eliminate bounds checks", this); | 4785 HPhase phase("H_Eliminate bounds checks", this); |
4449 BoundsCheckTable checks_table(zone()); | 4786 BoundsCheckTable checks_table(zone()); |
4450 EliminateRedundantBoundsChecks(entry_block(), &checks_table); | 4787 EliminateRedundantBoundsChecks(entry_block(), &checks_table); |
4788 if (FLAG_abcd_ivars) { | |
4789 EliminateRedundantBoundsChecksUsingInductionVariables(); | |
4790 } | |
4451 } | 4791 } |
4452 | 4792 |
4453 | 4793 |
4454 static void DehoistArrayIndex(ArrayInstructionInterface* array_operation) { | 4794 static void DehoistArrayIndex(ArrayInstructionInterface* array_operation) { |
4455 HValue* index = array_operation->GetKey()->ActualValue(); | 4795 HValue* index = array_operation->GetKey()->ActualValue(); |
4456 if (!index->representation().IsSmiOrInteger32()) return; | 4796 if (!index->representation().IsSmiOrInteger32()) return; |
4457 | 4797 |
4458 HConstant* constant; | 4798 HConstant* constant; |
4459 HValue* subexpression; | 4799 HValue* subexpression; |
4460 int32_t sign; | 4800 int32_t sign; |
(...skipping 7192 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
11653 } | 11993 } |
11654 } | 11994 } |
11655 | 11995 |
11656 #ifdef DEBUG | 11996 #ifdef DEBUG |
11657 if (graph_ != NULL) graph_->Verify(false); // No full verify. | 11997 if (graph_ != NULL) graph_->Verify(false); // No full verify. |
11658 if (allocator_ != NULL) allocator_->Verify(); | 11998 if (allocator_ != NULL) allocator_->Verify(); |
11659 #endif | 11999 #endif |
11660 } | 12000 } |
11661 | 12001 |
11662 } } // namespace v8::internal | 12002 } } // namespace v8::internal |
OLD | NEW |