OLD | NEW |
---|---|
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 |
OLD | NEW |