Chromium Code Reviews| 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 |