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

Side by Side Diff: src/hydrogen.cc

Issue 14676011: Improve dead code elimination by transitively marking live code and removing all dead code. Replace… (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Rename CanBeEliminated -> CannotBeEliminated, implement IsDeletable() for HPhi. Created 7 years, 7 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
« no previous file with comments | « src/hydrogen.h ('k') | src/hydrogen-instructions.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 86 matching lines...) Expand 10 before | Expand all | Expand 10 after
97 void HBasicBlock::AddPhi(HPhi* phi) { 97 void HBasicBlock::AddPhi(HPhi* phi) {
98 ASSERT(!IsStartBlock()); 98 ASSERT(!IsStartBlock());
99 phis_.Add(phi, zone()); 99 phis_.Add(phi, zone());
100 phi->SetBlock(this); 100 phi->SetBlock(this);
101 } 101 }
102 102
103 103
104 void HBasicBlock::RemovePhi(HPhi* phi) { 104 void HBasicBlock::RemovePhi(HPhi* phi) {
105 ASSERT(phi->block() == this); 105 ASSERT(phi->block() == this);
106 ASSERT(phis_.Contains(phi)); 106 ASSERT(phis_.Contains(phi));
107 ASSERT(phi->HasNoUses() || !phi->is_live());
108 phi->Kill(); 107 phi->Kill();
109 phis_.RemoveElement(phi); 108 phis_.RemoveElement(phi);
110 phi->SetBlock(NULL); 109 phi->SetBlock(NULL);
111 } 110 }
112 111
113 112
114 void HBasicBlock::AddInstruction(HInstruction* instr) { 113 void HBasicBlock::AddInstruction(HInstruction* instr) {
115 ASSERT(!IsStartBlock() || !IsFinished()); 114 ASSERT(!IsStartBlock() || !IsFinished());
116 ASSERT(!instr->IsLinked()); 115 ASSERT(!instr->IsLinked());
117 ASSERT(!IsFinished()); 116 ASSERT(!IsFinished());
(...skipping 2486 matching lines...) Expand 10 before | Expand all | Expand 10 after
2604 // Make sure that we *really* removed all redundant phis. 2603 // Make sure that we *really* removed all redundant phis.
2605 for (int i = 0; i < blocks_.length(); ++i) { 2604 for (int i = 0; i < blocks_.length(); ++i) {
2606 for (int j = 0; j < blocks_[i]->phis()->length(); j++) { 2605 for (int j = 0; j < blocks_[i]->phis()->length(); j++) {
2607 ASSERT(blocks_[i]->phis()->at(j)->GetRedundantReplacement() == NULL); 2606 ASSERT(blocks_[i]->phis()->at(j)->GetRedundantReplacement() == NULL);
2608 } 2607 }
2609 } 2608 }
2610 #endif 2609 #endif
2611 } 2610 }
2612 2611
2613 2612
2614 void HGraph::EliminateUnreachablePhis() {
2615 HPhase phase("H_Unreachable phi elimination", this);
2616
2617 // Initialize worklist.
2618 ZoneList<HPhi*> phi_list(blocks_.length(), zone());
2619 ZoneList<HPhi*> worklist(blocks_.length(), zone());
2620 for (int i = 0; i < blocks_.length(); ++i) {
2621 for (int j = 0; j < blocks_[i]->phis()->length(); j++) {
2622 HPhi* phi = blocks_[i]->phis()->at(j);
2623 phi_list.Add(phi, zone());
2624 // We can't eliminate phis in the receiver position in the environment
2625 // because in case of throwing an error we need this value to
2626 // construct a stack trace.
2627 if (phi->HasRealUses() || phi->IsReceiver()) {
2628 phi->set_is_live(true);
2629 worklist.Add(phi, zone());
2630 }
2631 }
2632 }
2633
2634 // Iteratively mark live phis.
2635 while (!worklist.is_empty()) {
2636 HPhi* phi = worklist.RemoveLast();
2637 for (int i = 0; i < phi->OperandCount(); i++) {
2638 HValue* operand = phi->OperandAt(i);
2639 if (operand->IsPhi() && !HPhi::cast(operand)->is_live()) {
2640 HPhi::cast(operand)->set_is_live(true);
2641 worklist.Add(HPhi::cast(operand), zone());
2642 }
2643 }
2644 }
2645
2646 // Remove unreachable phis.
2647 for (int i = 0; i < phi_list.length(); i++) {
2648 HPhi* phi = phi_list[i];
2649 if (!phi->is_live()) {
2650 HBasicBlock* block = phi->block();
2651 block->RemovePhi(phi);
2652 block->RecordDeletedPhi(phi->merged_index());
2653 }
2654 }
2655 }
2656
2657
2658 bool HGraph::CheckArgumentsPhiUses() { 2613 bool HGraph::CheckArgumentsPhiUses() {
2659 int block_count = blocks_.length(); 2614 int block_count = blocks_.length();
2660 for (int i = 0; i < block_count; ++i) { 2615 for (int i = 0; i < block_count; ++i) {
2661 for (int j = 0; j < blocks_[i]->phis()->length(); ++j) { 2616 for (int j = 0; j < blocks_[i]->phis()->length(); ++j) {
2662 HPhi* phi = blocks_[i]->phis()->at(j); 2617 HPhi* phi = blocks_[i]->phis()->at(j);
2663 // We don't support phi uses of arguments for now. 2618 // We don't support phi uses of arguments for now.
2664 if (phi->CheckFlag(HValue::kIsArguments)) return false; 2619 if (phi->CheckFlag(HValue::kIsArguments)) return false;
2665 } 2620 }
2666 } 2621 }
2667 return true; 2622 return true;
(...skipping 2240 matching lines...) Expand 10 before | Expand all | Expand 10 after
4908 *bailout_reason = SmartArrayPointer<char>(StrDup( 4863 *bailout_reason = SmartArrayPointer<char>(StrDup(
4909 "Unsupported phi use of const variable")); 4864 "Unsupported phi use of const variable"));
4910 return false; 4865 return false;
4911 } 4866 }
4912 EliminateRedundantPhis(); 4867 EliminateRedundantPhis();
4913 if (!CheckArgumentsPhiUses()) { 4868 if (!CheckArgumentsPhiUses()) {
4914 *bailout_reason = SmartArrayPointer<char>(StrDup( 4869 *bailout_reason = SmartArrayPointer<char>(StrDup(
4915 "Unsupported phi use of arguments")); 4870 "Unsupported phi use of arguments"));
4916 return false; 4871 return false;
4917 } 4872 }
4918 if (FLAG_eliminate_dead_phis) EliminateUnreachablePhis(); 4873
4874 // Remove dead code and phis
4875 if (FLAG_dead_code_elimination) {
4876 DeadCodeElimination("H_Eliminate early dead code");
4877 }
4919 CollectPhis(); 4878 CollectPhis();
4920 4879
4921 if (has_osr_loop_entry()) { 4880 if (has_osr_loop_entry()) {
4922 const ZoneList<HPhi*>* phis = osr_loop_entry()->phis(); 4881 const ZoneList<HPhi*>* phis = osr_loop_entry()->phis();
4923 for (int j = 0; j < phis->length(); j++) { 4882 for (int j = 0; j < phis->length(); j++) {
4924 HPhi* phi = phis->at(j); 4883 HPhi* phi = phis->at(j);
4925 osr_values()->at(phi->merged_index())->set_incoming_value(phi); 4884 osr_values()->at(phi->merged_index())->set_incoming_value(phi);
4926 } 4885 }
4927 } 4886 }
4928 4887
(...skipping 27 matching lines...) Expand all
4956 4915
4957 // Eliminate redundant stack checks on backwards branches. 4916 // Eliminate redundant stack checks on backwards branches.
4958 HStackCheckEliminator sce(this); 4917 HStackCheckEliminator sce(this);
4959 sce.Process(); 4918 sce.Process();
4960 4919
4961 if (FLAG_idefs) SetupInformativeDefinitions(); 4920 if (FLAG_idefs) SetupInformativeDefinitions();
4962 if (FLAG_array_bounds_checks_elimination && !FLAG_idefs) { 4921 if (FLAG_array_bounds_checks_elimination && !FLAG_idefs) {
4963 EliminateRedundantBoundsChecks(); 4922 EliminateRedundantBoundsChecks();
4964 } 4923 }
4965 if (FLAG_array_index_dehoisting) DehoistSimpleArrayIndexComputations(); 4924 if (FLAG_array_index_dehoisting) DehoistSimpleArrayIndexComputations();
4966 if (FLAG_dead_code_elimination) DeadCodeElimination(); 4925 if (FLAG_dead_code_elimination) {
4926 DeadCodeElimination("H_Eliminate late dead code");
4927 }
4967 4928
4968 RestoreActualValues(); 4929 RestoreActualValues();
4969 4930
4970 return true; 4931 return true;
4971 } 4932 }
4972 4933
4973 4934
4974 void HGraph::SetupInformativeDefinitionsInBlock(HBasicBlock* block) { 4935 void HGraph::SetupInformativeDefinitionsInBlock(HBasicBlock* block) {
4975 for (int phi_index = 0; phi_index < block->phis()->length(); phi_index++) { 4936 for (int phi_index = 0; phi_index < block->phis()->length(); phi_index++) {
4976 HPhi* phi = block->phis()->at(phi_index); 4937 HPhi* phi = block->phis()->at(phi_index);
(...skipping 456 matching lines...) Expand 10 before | Expand all | Expand 10 after
5433 array_instruction = static_cast<ArrayInstructionInterface*>(op); 5394 array_instruction = static_cast<ArrayInstructionInterface*>(op);
5434 } else { 5395 } else {
5435 continue; 5396 continue;
5436 } 5397 }
5437 DehoistArrayIndex(array_instruction); 5398 DehoistArrayIndex(array_instruction);
5438 } 5399 }
5439 } 5400 }
5440 } 5401 }
5441 5402
5442 5403
5443 void HGraph::DeadCodeElimination() { 5404 void HGraph::DeadCodeElimination(const char* phase_name) {
5444 HPhase phase("H_Dead code elimination", this); 5405 HPhase phase(phase_name, this);
5445 ZoneList<HInstruction*> worklist(blocks_.length(), zone()); 5406 MarkLiveInstructions();
5407 RemoveDeadInstructions();
5408 }
5409
5410
5411 void HGraph::MarkLiveInstructions() {
5412 ZoneList<HValue*> worklist(blocks_.length(), zone());
5413
5414 // Mark initial root instructions for dead code elimination.
5446 for (int i = 0; i < blocks()->length(); ++i) { 5415 for (int i = 0; i < blocks()->length(); ++i) {
5447 for (HInstruction* instr = blocks()->at(i)->first(); 5416 HBasicBlock* block = blocks()->at(i);
5417 for (HInstruction* instr = block->first();
5448 instr != NULL; 5418 instr != NULL;
5449 instr = instr->next()) { 5419 instr = instr->next()) {
5450 if (instr->IsDead()) worklist.Add(instr, zone()); 5420 if (instr->CannotBeEliminated()) MarkLive(NULL, instr, &worklist);
5421 }
5422 for (int j = 0; j < block->phis()->length(); j++) {
5423 HPhi* phi = block->phis()->at(j);
5424 if (phi->CannotBeEliminated()) MarkLive(NULL, phi, &worklist);
5451 } 5425 }
5452 } 5426 }
5453 5427
5428 // Transitively mark all inputs of live instructions live.
5454 while (!worklist.is_empty()) { 5429 while (!worklist.is_empty()) {
5455 HInstruction* instr = worklist.RemoveLast(); 5430 HValue* instr = worklist.RemoveLast();
5456 // This happens when an instruction is used multiple times as operand. That
5457 // in turn could happen through GVN.
5458 if (!instr->IsLinked()) continue;
5459 if (FLAG_trace_dead_code_elimination) {
5460 HeapStringAllocator allocator;
5461 StringStream stream(&allocator);
5462 instr->PrintNameTo(&stream);
5463 stream.Add(" = ");
5464 instr->PrintTo(&stream);
5465 PrintF("[removing dead instruction %s]\n", *stream.ToCString());
5466 }
5467 instr->DeleteAndReplaceWith(NULL);
5468 for (int i = 0; i < instr->OperandCount(); ++i) { 5431 for (int i = 0; i < instr->OperandCount(); ++i) {
5469 HValue* operand = instr->OperandAt(i); 5432 MarkLive(instr, instr->OperandAt(i), &worklist);
5470 if (operand->IsDead()) worklist.Add(HInstruction::cast(operand), zone());
5471 } 5433 }
5472 } 5434 }
5473 } 5435 }
5474 5436
5437
5438 void HGraph::MarkLive(HValue *ref, HValue* instr,
5439 ZoneList<HValue*>* worklist) {
5440 if (!instr->CheckFlag(HValue::kIsLive)) {
5441 instr->SetFlag(HValue::kIsLive);
5442 worklist->Add(instr, zone());
5443
5444 if (FLAG_trace_dead_code_elimination) {
5445 HeapStringAllocator allocator;
5446 StringStream stream(&allocator);
5447 if (ref != NULL) {
5448 ref->PrintTo(&stream);
5449 } else {
5450 stream.Add("root ");
5451 }
5452 stream.Add(" -> ");
5453 instr->PrintTo(&stream);
5454 PrintF("[MarkLive %s]\n", *stream.ToCString());
5455 }
5456 }
5457 }
5458
5459
5460 void HGraph::RemoveDeadInstructions() {
5461 ZoneList<HPhi*> dead_phis(blocks_.length(), zone());
5462
5463 // Remove any instruction not marked kIsLive.
5464 for (int i = 0; i < blocks()->length(); ++i) {
5465 HBasicBlock* block = blocks()->at(i);
5466 for (HInstruction* instr = block->first();
5467 instr != NULL;
5468 instr = instr->next()) {
5469 if (!instr->CheckFlag(HValue::kIsLive)) {
5470 // Instruction has not been marked live; assume it is dead and remove.
5471 // TODO(titzer): we don't remove constants because some special ones
5472 // might be used by later phases and are assumed to be in the graph
5473 if (instr->IsConstant()) instr->DeleteAndReplaceWith(NULL);
5474 } else {
5475 // Clear the liveness flag to leave the graph clean for the next DCE.
5476 instr->ClearFlag(HValue::kIsLive);
5477 }
5478 }
5479 // Collect phis that are dead and remove them in the next pass.
5480 for (int j = 0; j < block->phis()->length(); j++) {
5481 HPhi* phi = block->phis()->at(j);
5482 if (!phi->CheckFlag(HValue::kIsLive)) {
5483 dead_phis.Add(phi, zone());
5484 } else {
5485 phi->ClearFlag(HValue::kIsLive);
5486 }
5487 }
5488 }
5489
5490 // Process phis separately to avoid simultaneously mutating the phi list.
5491 while (!dead_phis.is_empty()) {
5492 HPhi* phi = dead_phis.RemoveLast();
5493 HBasicBlock* block = phi->block();
5494 phi->DeleteAndReplaceWith(NULL);
5495 block->RecordDeletedPhi(phi->merged_index());
5496 }
5497 }
5498
5475 5499
5476 void HGraph::RestoreActualValues() { 5500 void HGraph::RestoreActualValues() {
5477 HPhase phase("H_Restore actual values", this); 5501 HPhase phase("H_Restore actual values", this);
5478 5502
5479 for (int block_index = 0; block_index < blocks()->length(); block_index++) { 5503 for (int block_index = 0; block_index < blocks()->length(); block_index++) {
5480 HBasicBlock* block = blocks()->at(block_index); 5504 HBasicBlock* block = blocks()->at(block_index);
5481 5505
5482 #ifdef DEBUG 5506 #ifdef DEBUG
5483 for (int i = 0; i < block->phis()->length(); i++) { 5507 for (int i = 0; i < block->phis()->length(); i++) {
5484 HPhi* phi = block->phis()->at(i); 5508 HPhi* phi = block->phis()->at(i);
(...skipping 6933 matching lines...) Expand 10 before | Expand all | Expand 10 after
12418 } 12442 }
12419 } 12443 }
12420 12444
12421 #ifdef DEBUG 12445 #ifdef DEBUG
12422 if (graph_ != NULL) graph_->Verify(false); // No full verify. 12446 if (graph_ != NULL) graph_->Verify(false); // No full verify.
12423 if (allocator_ != NULL) allocator_->Verify(); 12447 if (allocator_ != NULL) allocator_->Verify();
12424 #endif 12448 #endif
12425 } 12449 }
12426 12450
12427 } } // namespace v8::internal 12451 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/hydrogen.h ('k') | src/hydrogen-instructions.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698