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(); | |
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::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 Loading... | |
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 |
OLD | NEW |