Index: src/hydrogen.cc |
diff --git a/src/hydrogen.cc b/src/hydrogen.cc |
index 58a9b78750bb7401bfdc9e167800f8f01d3ef078..7a8e9dd66446a92b8e9e565d359718164cdfa59e 100644 |
--- a/src/hydrogen.cc |
+++ b/src/hydrogen.cc |
@@ -104,7 +104,6 @@ void HBasicBlock::AddPhi(HPhi* phi) { |
void HBasicBlock::RemovePhi(HPhi* phi) { |
ASSERT(phi->block() == this); |
ASSERT(phis_.Contains(phi)); |
- ASSERT(phi->HasNoUses() || !phi->is_live()); |
phi->Kill(); |
phis_.RemoveElement(phi); |
phi->SetBlock(NULL); |
@@ -2594,50 +2593,6 @@ void HGraph::EliminateRedundantPhis() { |
} |
-void HGraph::EliminateUnreachablePhis() { |
- HPhase phase("H_Unreachable phi elimination", this); |
- |
- // Initialize worklist. |
- ZoneList<HPhi*> phi_list(blocks_.length(), zone()); |
- ZoneList<HPhi*> worklist(blocks_.length(), zone()); |
- for (int i = 0; i < blocks_.length(); ++i) { |
- for (int j = 0; j < blocks_[i]->phis()->length(); j++) { |
- HPhi* phi = blocks_[i]->phis()->at(j); |
- phi_list.Add(phi, zone()); |
- // We can't eliminate phis in the receiver position in the environment |
- // because in case of throwing an error we need this value to |
- // construct a stack trace. |
- if (phi->HasRealUses() || phi->IsReceiver()) { |
- phi->set_is_live(true); |
- worklist.Add(phi, zone()); |
- } |
- } |
- } |
- |
- // Iteratively mark live phis. |
- while (!worklist.is_empty()) { |
- HPhi* phi = worklist.RemoveLast(); |
- for (int i = 0; i < phi->OperandCount(); i++) { |
- HValue* operand = phi->OperandAt(i); |
- if (operand->IsPhi() && !HPhi::cast(operand)->is_live()) { |
- HPhi::cast(operand)->set_is_live(true); |
- worklist.Add(HPhi::cast(operand), zone()); |
- } |
- } |
- } |
- |
- // Remove unreachable phis. |
- for (int i = 0; i < phi_list.length(); i++) { |
- HPhi* phi = phi_list[i]; |
- if (!phi->is_live()) { |
- HBasicBlock* block = phi->block(); |
- block->RemovePhi(phi); |
- block->RecordDeletedPhi(phi->merged_index()); |
- } |
- } |
-} |
- |
- |
bool HGraph::CheckArgumentsPhiUses() { |
int block_count = blocks_.length(); |
for (int i = 0; i < block_count; ++i) { |
@@ -4898,7 +4853,9 @@ bool HGraph::Optimize(SmartArrayPointer<char>* bailout_reason) { |
"Unsupported phi use of arguments")); |
return false; |
} |
- if (FLAG_eliminate_dead_phis) EliminateUnreachablePhis(); |
+ |
+ // Remove dead code and phis |
+ 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.
|
CollectPhis(); |
if (has_osr_loop_entry()) { |
@@ -5423,34 +5380,85 @@ void HGraph::DehoistSimpleArrayIndexComputations() { |
} |
+void HGraph::MarkNotDead(HValue *ref, HValue* instr, |
+ ZoneList<HValue*>* worklist) { |
+ if (!instr->CheckFlag(HValue::kIsNotDead)) { |
+ instr->SetFlag(HValue::kIsNotDead); |
+ worklist->Add(instr, zone()); |
+ |
+ if (FLAG_trace_dead_code_elimination) { |
+ 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
|
+ HeapStringAllocator allocator; |
+ StringStream stream(&allocator); |
+ if (ref != NULL) ref->PrintNameTo(&stream); |
+ stream.Add(" -> "); |
+ instr->PrintNameTo(&stream); |
+ PrintF("[MarkNotDead %s]\n", *stream.ToCString()); |
+ } |
+ } |
+} |
+ |
+ |
+bool HGraph::TryDeadCodeElimination(HValue* instr) { |
+ if (!instr->CheckFlag(HValue::kIsNotDead)) { |
+ // instruction has not been marked live. assume it is dead and remove. |
+ // TODO(titzer): we don't remove constants because some special constants |
+ // might be used by later phases and are assumed to be in the graph |
+ if (!instr->IsConstant()) instr->DeleteAndReplaceWith(NULL); |
+ return true; |
+ } else { |
+ // clear the liveness flag to leave the graph clean for the next DCE |
+ instr->ClearFlag(HValue::kIsNotDead); |
+ return false; |
+ } |
+} |
+ |
+ |
void HGraph::DeadCodeElimination() { |
HPhase phase("H_Dead code elimination", this); |
- ZoneList<HInstruction*> worklist(blocks_.length(), zone()); |
+ ZoneList<HValue*> worklist(blocks_.length(), zone()); |
+ 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
|
+ |
+ // mark initial root instructions for dead code elimination |
for (int i = 0; i < blocks()->length(); ++i) { |
- for (HInstruction* instr = blocks()->at(i)->first(); |
+ HBasicBlock* block = blocks()->at(i); |
+ for (HInstruction* instr = block->first(); |
instr != NULL; |
instr = instr->next()) { |
- if (instr->IsDead()) worklist.Add(instr, zone()); |
+ if (instr->IsNotDeletable()) MarkNotDead(NULL, instr, &worklist); |
+ } |
+ // TODO(titzer): we can't eliminate the receiver for generating backtraces |
+ for (int j = 0; j < block->phis()->length(); j++) { |
+ HPhi* phi = block->phis()->at(j); |
+ if (phi->IsReceiver()) MarkNotDead(NULL, phi, &worklist); |
+ philist.Add(phi, zone()); |
} |
} |
+ // transitively mark all inputs of live instructions live |
while (!worklist.is_empty()) { |
- HInstruction* instr = worklist.RemoveLast(); |
- // This happens when an instruction is used multiple times as operand. That |
- // in turn could happen through GVN. |
- if (!instr->IsLinked()) continue; |
- if (FLAG_trace_dead_code_elimination) { |
- HeapStringAllocator allocator; |
- StringStream stream(&allocator); |
- instr->PrintNameTo(&stream); |
- stream.Add(" = "); |
- instr->PrintTo(&stream); |
- PrintF("[removing dead instruction %s]\n", *stream.ToCString()); |
- } |
- instr->DeleteAndReplaceWith(NULL); |
+ HValue* instr = worklist.RemoveLast(); |
for (int i = 0; i < instr->OperandCount(); ++i) { |
- HValue* operand = instr->OperandAt(i); |
- if (operand->IsDead()) worklist.Add(HInstruction::cast(operand), zone()); |
+ MarkNotDead(instr, instr->OperandAt(i), &worklist); |
+ } |
+ } |
+ |
+ // remove any instruction not marked in the previous phase |
+ for (int i = 0; i < blocks()->length(); ++i) { |
+ HBasicBlock* block = blocks()->at(i); |
+ for (HInstruction* instr = block->first(); |
+ instr != NULL; |
+ instr = instr->next()) { |
+ TryDeadCodeElimination(instr); |
+ } |
+ } |
+ |
+ // process phis separately because dead ones need to be recorded |
+ while (!philist.is_empty()) { |
+ HPhi* phi = philist.RemoveLast(); |
+ HBasicBlock* block = phi->block(); |
+ if (TryDeadCodeElimination(phi)) { |
+ block->RecordDeletedPhi(phi->merged_index()); |
} |
} |
} |