Chromium Code Reviews| 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 |