Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(453)

Side by Side Diff: src/hydrogen.cc

Issue 17568015: New array bounds check elimination pass (focused on induction variables and bitwise operations). (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Created 7 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698