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

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: Comment fix. 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
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 2469 matching lines...) Expand 10 before | Expand all | Expand 10 after
2587 // Make sure that we *really* removed all redundant phis. 2586 // Make sure that we *really* removed all redundant phis.
2588 for (int i = 0; i < blocks_.length(); ++i) { 2587 for (int i = 0; i < blocks_.length(); ++i) {
2589 for (int j = 0; j < blocks_[i]->phis()->length(); j++) { 2588 for (int j = 0; j < blocks_[i]->phis()->length(); j++) {
2590 ASSERT(blocks_[i]->phis()->at(j)->GetRedundantReplacement() == NULL); 2589 ASSERT(blocks_[i]->phis()->at(j)->GetRedundantReplacement() == NULL);
2591 } 2590 }
2592 } 2591 }
2593 #endif 2592 #endif
2594 } 2593 }
2595 2594
2596 2595
2597 void HGraph::EliminateUnreachablePhis() {
2598 HPhase phase("H_Unreachable phi elimination", this);
2599
2600 // Initialize worklist.
2601 ZoneList<HPhi*> phi_list(blocks_.length(), zone());
2602 ZoneList<HPhi*> worklist(blocks_.length(), zone());
2603 for (int i = 0; i < blocks_.length(); ++i) {
2604 for (int j = 0; j < blocks_[i]->phis()->length(); j++) {
2605 HPhi* phi = blocks_[i]->phis()->at(j);
2606 phi_list.Add(phi, zone());
2607 // We can't eliminate phis in the receiver position in the environment
2608 // because in case of throwing an error we need this value to
2609 // construct a stack trace.
2610 if (phi->HasRealUses() || phi->IsReceiver()) {
2611 phi->set_is_live(true);
2612 worklist.Add(phi, zone());
2613 }
2614 }
2615 }
2616
2617 // Iteratively mark live phis.
2618 while (!worklist.is_empty()) {
2619 HPhi* phi = worklist.RemoveLast();
2620 for (int i = 0; i < phi->OperandCount(); i++) {
2621 HValue* operand = phi->OperandAt(i);
2622 if (operand->IsPhi() && !HPhi::cast(operand)->is_live()) {
2623 HPhi::cast(operand)->set_is_live(true);
2624 worklist.Add(HPhi::cast(operand), zone());
2625 }
2626 }
2627 }
2628
2629 // Remove unreachable phis.
2630 for (int i = 0; i < phi_list.length(); i++) {
2631 HPhi* phi = phi_list[i];
2632 if (!phi->is_live()) {
2633 HBasicBlock* block = phi->block();
2634 block->RemovePhi(phi);
2635 block->RecordDeletedPhi(phi->merged_index());
2636 }
2637 }
2638 }
2639
2640
2641 bool HGraph::CheckArgumentsPhiUses() { 2596 bool HGraph::CheckArgumentsPhiUses() {
2642 int block_count = blocks_.length(); 2597 int block_count = blocks_.length();
2643 for (int i = 0; i < block_count; ++i) { 2598 for (int i = 0; i < block_count; ++i) {
2644 for (int j = 0; j < blocks_[i]->phis()->length(); ++j) { 2599 for (int j = 0; j < blocks_[i]->phis()->length(); ++j) {
2645 HPhi* phi = blocks_[i]->phis()->at(j); 2600 HPhi* phi = blocks_[i]->phis()->at(j);
2646 // We don't support phi uses of arguments for now. 2601 // We don't support phi uses of arguments for now.
2647 if (phi->CheckFlag(HValue::kIsArguments)) return false; 2602 if (phi->CheckFlag(HValue::kIsArguments)) return false;
2648 } 2603 }
2649 } 2604 }
2650 return true; 2605 return true;
(...skipping 2240 matching lines...) Expand 10 before | Expand all | Expand 10 after
4891 *bailout_reason = SmartArrayPointer<char>(StrDup( 4846 *bailout_reason = SmartArrayPointer<char>(StrDup(
4892 "Unsupported phi use of const variable")); 4847 "Unsupported phi use of const variable"));
4893 return false; 4848 return false;
4894 } 4849 }
4895 EliminateRedundantPhis(); 4850 EliminateRedundantPhis();
4896 if (!CheckArgumentsPhiUses()) { 4851 if (!CheckArgumentsPhiUses()) {
4897 *bailout_reason = SmartArrayPointer<char>(StrDup( 4852 *bailout_reason = SmartArrayPointer<char>(StrDup(
4898 "Unsupported phi use of arguments")); 4853 "Unsupported phi use of arguments"));
4899 return false; 4854 return false;
4900 } 4855 }
4901 if (FLAG_eliminate_dead_phis) EliminateUnreachablePhis(); 4856
4857 // Remove dead code and phis
4858 if (FLAG_dead_code_elimination) DeadCodeElimination();
4902 CollectPhis(); 4859 CollectPhis();
4903 4860
4904 if (has_osr_loop_entry()) { 4861 if (has_osr_loop_entry()) {
4905 const ZoneList<HPhi*>* phis = osr_loop_entry()->phis(); 4862 const ZoneList<HPhi*>* phis = osr_loop_entry()->phis();
4906 for (int j = 0; j < phis->length(); j++) { 4863 for (int j = 0; j < phis->length(); j++) {
4907 HPhi* phi = phis->at(j); 4864 HPhi* phi = phis->at(j);
4908 osr_values()->at(phi->merged_index())->set_incoming_value(phi); 4865 osr_values()->at(phi->merged_index())->set_incoming_value(phi);
4909 } 4866 }
4910 } 4867 }
4911 4868
(...skipping 504 matching lines...) Expand 10 before | Expand all | Expand 10 after
5416 array_instruction = static_cast<ArrayInstructionInterface*>(op); 5373 array_instruction = static_cast<ArrayInstructionInterface*>(op);
5417 } else { 5374 } else {
5418 continue; 5375 continue;
5419 } 5376 }
5420 DehoistArrayIndex(array_instruction); 5377 DehoistArrayIndex(array_instruction);
5421 } 5378 }
5422 } 5379 }
5423 } 5380 }
5424 5381
5425 5382
5383 void HGraph::MarkLive(HValue *ref, HValue* instr,
5384 ZoneList<HValue*>* worklist) {
5385 if (!instr->CheckFlag(HValue::kIsLive)) {
5386 instr->SetFlag(HValue::kIsLive);
5387 worklist->Add(instr, zone());
5388
5389 if (FLAG_trace_dead_code_elimination) {
5390 HeapStringAllocator allocator;
5391 StringStream stream(&allocator);
5392 if (ref != NULL) ref->PrintNameTo(&stream);
Sven Panne 2013/05/13 09:31:55 Please print the full instruction here, not just t
titzer 2013/05/13 13:29:39 Done.
Sven Panne 2013/05/13 14:55:52 Again, I don't see the "Done" part, perhaps you fo
titzer 2013/05/13 18:11:13 ...
5393 stream.Add(" -> ");
5394 instr->PrintNameTo(&stream);
5395 PrintF("[MarkLive %s]\n", *stream.ToCString());
5396 }
5397 }
5398 }
5399
5400
5401 bool HGraph::TryDeadCodeElimination(HValue* instr) {
Sven Panne 2013/05/13 09:31:55 I think this helper method is actually less clear
titzer 2013/05/13 13:29:39 I would go for inlining if it weren't used in two
Sven Panne 2013/05/13 14:55:52 If you insist of keeping it, then make it at least
titzer 2013/05/13 18:11:13 I've inlined it and split the main algorithm into
5402 if (!instr->CheckFlag(HValue::kIsLive)) {
5403 // Instruction has not been marked live; assume it is dead and remove.
5404 // TODO(titzer): we don't remove constants because some special constants
5405 // might be used by later phases and are assumed to be in the graph
5406 if (!instr->IsConstant()) instr->DeleteAndReplaceWith(NULL);
5407 return true;
5408 } else {
5409 // Clear the liveness flag to leave the graph clean for the next DCE.
5410 instr->ClearFlag(HValue::kIsLive);
5411 return false;
5412 }
5413 }
5414
5415
5426 void HGraph::DeadCodeElimination() { 5416 void HGraph::DeadCodeElimination() {
5427 HPhase phase("H_Dead code elimination", this); 5417 HPhase phase("H_Dead code elimination", this);
Sven Panne 2013/05/13 09:31:55 We call this phase twice, so it would be good to n
titzer 2013/05/13 13:29:39 Done.
Sven Panne 2013/05/13 14:55:52 Where? :-)
titzer 2013/05/13 18:11:13 Done.
5428 ZoneList<HInstruction*> worklist(blocks_.length(), zone()); 5418 ZoneList<HValue*> worklist(blocks_.length(), zone());
5419 ZoneList<HPhi*> philist(blocks_.length(), zone());
Sven Panne 2013/05/13 09:31:55 As Jakob already pointed out, I don't think we nee
titzer 2013/05/13 13:29:39 I forgot to hit "send" on a previous set of commen
Sven Panne 2013/05/13 14:55:52 Then rename it to phi_snapshot, making it's purpos
titzer 2013/05/13 18:11:13 I'm going with your latter suggestion to make a se
5420
5421 // Mark initial root instructions for dead code elimination.
Sven Panne 2013/05/13 09:31:55 Replace this comment and the ones below by extract
titzer 2013/05/13 13:29:39 Normally I would agree with breaking things into s
Sven Panne 2013/05/13 14:55:52 In my opinion this is a *very* worthwhile refactor
titzer 2013/05/13 18:11:13 I'm gonna go ahead and disagree with Bob on this o
5429 for (int i = 0; i < blocks()->length(); ++i) { 5422 for (int i = 0; i < blocks()->length(); ++i) {
5430 for (HInstruction* instr = blocks()->at(i)->first(); 5423 HBasicBlock* block = blocks()->at(i);
5424 for (HInstruction* instr = block->first();
5431 instr != NULL; 5425 instr != NULL;
5432 instr = instr->next()) { 5426 instr = instr->next()) {
5433 if (instr->IsDead()) worklist.Add(instr, zone()); 5427 if (!instr->CanBeEliminated()) MarkLive(NULL, instr, &worklist);
5428 }
5429 // TODO(titzer): we can't eliminate the receiver for generating backtraces
5430 for (int j = 0; j < block->phis()->length(); j++) {
5431 HPhi* phi = block->phis()->at(j);
5432 if (phi->IsReceiver()) MarkLive(NULL, phi, &worklist);
5433 philist.Add(phi, zone());
5434 } 5434 }
5435 } 5435 }
5436 5436
5437 // Transitively mark all inputs of live instructions live.
5437 while (!worklist.is_empty()) { 5438 while (!worklist.is_empty()) {
5438 HInstruction* instr = worklist.RemoveLast(); 5439 HValue* instr = worklist.RemoveLast();
5439 // This happens when an instruction is used multiple times as operand. That 5440 for (int i = 0; i < instr->OperandCount(); ++i) {
5440 // in turn could happen through GVN. 5441 MarkLive(instr, instr->OperandAt(i), &worklist);
5441 if (!instr->IsLinked()) continue;
5442 if (FLAG_trace_dead_code_elimination) {
5443 HeapStringAllocator allocator;
5444 StringStream stream(&allocator);
5445 instr->PrintNameTo(&stream);
5446 stream.Add(" = ");
5447 instr->PrintTo(&stream);
5448 PrintF("[removing dead instruction %s]\n", *stream.ToCString());
5449 } 5442 }
5450 instr->DeleteAndReplaceWith(NULL); 5443 }
5451 for (int i = 0; i < instr->OperandCount(); ++i) { 5444
5452 HValue* operand = instr->OperandAt(i); 5445 // Remove any instruction not marked in the previous phase.
5453 if (operand->IsDead()) worklist.Add(HInstruction::cast(operand), zone()); 5446 for (int i = 0; i < blocks()->length(); ++i) {
5447 HBasicBlock* block = blocks()->at(i);
5448 for (HInstruction* instr = block->first();
5449 instr != NULL;
5450 instr = instr->next()) {
5451 TryDeadCodeElimination(instr);
5452 }
5453 }
5454
5455 // Process phis separately because dead ones need to be recorded.
5456 while (!philist.is_empty()) {
Sven Panne 2013/05/13 09:31:55 Just fold this into the previous loop, no need for
titzer 2013/05/13 13:29:39 See above; we can't because the phi list of a bloc
Sven Panne 2013/05/13 14:55:52 An alternative approach would be folding this into
titzer 2013/05/13 18:11:13 Yeah, that's a better idea.
5457 HPhi* phi = philist.RemoveLast();
5458 HBasicBlock* block = phi->block();
5459 if (TryDeadCodeElimination(phi)) {
5460 block->RecordDeletedPhi(phi->merged_index());
5454 } 5461 }
5455 } 5462 }
5456 } 5463 }
5457 5464
5458 5465
5459 void HGraph::RestoreActualValues() { 5466 void HGraph::RestoreActualValues() {
5460 HPhase phase("H_Restore actual values", this); 5467 HPhase phase("H_Restore actual values", this);
5461 5468
5462 for (int block_index = 0; block_index < blocks()->length(); block_index++) { 5469 for (int block_index = 0; block_index < blocks()->length(); block_index++) {
5463 HBasicBlock* block = blocks()->at(block_index); 5470 HBasicBlock* block = blocks()->at(block_index);
(...skipping 6809 matching lines...) Expand 10 before | Expand all | Expand 10 after
12273 } 12280 }
12274 } 12281 }
12275 12282
12276 #ifdef DEBUG 12283 #ifdef DEBUG
12277 if (graph_ != NULL) graph_->Verify(false); // No full verify. 12284 if (graph_ != NULL) graph_->Verify(false); // No full verify.
12278 if (allocator_ != NULL) allocator_->Verify(); 12285 if (allocator_ != NULL) allocator_->Verify();
12279 #endif 12286 #endif
12280 } 12287 }
12281 12288
12282 } } // namespace v8::internal 12289 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/hydrogen.h ('k') | src/hydrogen-instructions.h » ('j') | src/hydrogen-instructions.cc » ('J')

Powered by Google App Engine
This is Rietveld 408576698