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

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: 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();
Sven Panne 2013/05/07 13:32:10 I am not sure if this is what we want: Almost all
Jakob Kummerow 2013/05/08 12:07:24 As discussed offline, it's probably OK to leave th
titzer 2013/05/13 13:29:38 Leaving as one flag.
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::MarkNotDead(HValue *ref, HValue* instr,
5384 ZoneList<HValue*>* worklist) {
5385 if (!instr->CheckFlag(HValue::kIsNotDead)) {
5386 instr->SetFlag(HValue::kIsNotDead);
5387 worklist->Add(instr, zone());
5388
5389 if (FLAG_trace_dead_code_elimination) {
5390 ALLOW_HANDLE_DEREF(isolate(), "trace mode for deadcode");
Sven Panne 2013/05/07 13:32:10 Why exactly do we need this and why is this safe?
titzer 2013/05/13 13:29:38 I was debugging and printing the entire instructio
5391 HeapStringAllocator allocator;
5392 StringStream stream(&allocator);
5393 if (ref != NULL) ref->PrintNameTo(&stream);
5394 stream.Add(" -> ");
5395 instr->PrintNameTo(&stream);
5396 PrintF("[MarkNotDead %s]\n", *stream.ToCString());
5397 }
5398 }
5399 }
5400
5401
5402 bool HGraph::TryDeadCodeElimination(HValue* instr) {
5403 if (!instr->CheckFlag(HValue::kIsNotDead)) {
5404 // instruction has not been marked live. assume it is dead and remove.
5405 // TODO(titzer): we don't remove constants because some special constants
5406 // might be used by later phases and are assumed to be in the graph
5407 if (!instr->IsConstant()) instr->DeleteAndReplaceWith(NULL);
5408 return true;
5409 } else {
5410 // clear the liveness flag to leave the graph clean for the next DCE
5411 instr->ClearFlag(HValue::kIsNotDead);
5412 return false;
5413 }
5414 }
5415
5416
5426 void HGraph::DeadCodeElimination() { 5417 void HGraph::DeadCodeElimination() {
5427 HPhase phase("H_Dead code elimination", this); 5418 HPhase phase("H_Dead code elimination", this);
5428 ZoneList<HInstruction*> worklist(blocks_.length(), zone()); 5419 ZoneList<HValue*> worklist(blocks_.length(), zone());
5420 ZoneList<HPhi*> philist(blocks_.length(), zone());
Jakob Kummerow 2013/05/08 12:07:24 Why do we need this phi list at all? Can't we simp
titzer 2013/05/13 13:29:38 Because if the code iterates over the phi list as
5421
5422 // mark initial root instructions for dead code elimination
5429 for (int i = 0; i < blocks()->length(); ++i) { 5423 for (int i = 0; i < blocks()->length(); ++i) {
5430 for (HInstruction* instr = blocks()->at(i)->first(); 5424 HBasicBlock* block = blocks()->at(i);
5425 for (HInstruction* instr = block->first();
5431 instr != NULL; 5426 instr != NULL;
5432 instr = instr->next()) { 5427 instr = instr->next()) {
5433 if (instr->IsDead()) worklist.Add(instr, zone()); 5428 if (instr->IsNotDeletable()) MarkNotDead(NULL, instr, &worklist);
5429 }
5430 // TODO(titzer): we can't eliminate the receiver for generating backtraces
5431 for (int j = 0; j < block->phis()->length(); j++) {
5432 HPhi* phi = block->phis()->at(j);
5433 if (phi->IsReceiver()) MarkNotDead(NULL, phi, &worklist);
5434 philist.Add(phi, zone());
5434 } 5435 }
5435 } 5436 }
5436 5437
5438 // transitively mark all inputs of live instructions live
5437 while (!worklist.is_empty()) { 5439 while (!worklist.is_empty()) {
5438 HInstruction* instr = worklist.RemoveLast(); 5440 HValue* instr = worklist.RemoveLast();
5439 // This happens when an instruction is used multiple times as operand. That 5441 for (int i = 0; i < instr->OperandCount(); ++i) {
5440 // in turn could happen through GVN. 5442 MarkNotDead(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 } 5443 }
5450 instr->DeleteAndReplaceWith(NULL); 5444 }
5451 for (int i = 0; i < instr->OperandCount(); ++i) { 5445
5452 HValue* operand = instr->OperandAt(i); 5446 // remove any instruction not marked in the previous phase
5453 if (operand->IsDead()) worklist.Add(HInstruction::cast(operand), zone()); 5447 for (int i = 0; i < blocks()->length(); ++i) {
5448 HBasicBlock* block = blocks()->at(i);
5449 for (HInstruction* instr = block->first();
5450 instr != NULL;
5451 instr = instr->next()) {
5452 TryDeadCodeElimination(instr);
5453 }
5454 }
5455
5456 // process phis separately because dead ones need to be recorded
5457 while (!philist.is_empty()) {
5458 HPhi* phi = philist.RemoveLast();
5459 HBasicBlock* block = phi->block();
5460 if (TryDeadCodeElimination(phi)) {
5461 block->RecordDeletedPhi(phi->merged_index());
5454 } 5462 }
5455 } 5463 }
5456 } 5464 }
5457 5465
5458 5466
5459 void HGraph::RestoreActualValues() { 5467 void HGraph::RestoreActualValues() {
5460 HPhase phase("H_Restore actual values", this); 5468 HPhase phase("H_Restore actual values", this);
5461 5469
5462 for (int block_index = 0; block_index < blocks()->length(); block_index++) { 5470 for (int block_index = 0; block_index < blocks()->length(); block_index++) {
5463 HBasicBlock* block = blocks()->at(block_index); 5471 HBasicBlock* block = blocks()->at(block_index);
(...skipping 6809 matching lines...) Expand 10 before | Expand all | Expand 10 after
12273 } 12281 }
12274 } 12282 }
12275 12283
12276 #ifdef DEBUG 12284 #ifdef DEBUG
12277 if (graph_ != NULL) graph_->Verify(false); // No full verify. 12285 if (graph_ != NULL) graph_->Verify(false); // No full verify.
12278 if (allocator_ != NULL) allocator_->Verify(); 12286 if (allocator_ != NULL) allocator_->Verify();
12279 #endif 12287 #endif
12280 } 12288 }
12281 12289
12282 } } // namespace v8::internal 12290 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/hydrogen.h ('k') | src/hydrogen-instructions.h » ('j') | src/hydrogen-instructions.h » ('J')

Powered by Google App Engine
This is Rietveld 408576698