| Index: src/hydrogen-removable-simulates.cc
|
| diff --git a/src/hydrogen-removable-simulates.cc b/src/hydrogen-removable-simulates.cc
|
| index 7bbe3cbf284c8565bffd39cae88d5d1208fec4a6..738c7358f519288b137b90d53342f8d289f8d563 100644
|
| --- a/src/hydrogen-removable-simulates.cc
|
| +++ b/src/hydrogen-removable-simulates.cc
|
| @@ -2,84 +2,143 @@
|
| // Use of this source code is governed by a BSD-style license that can be
|
| // found in the LICENSE file.
|
|
|
| +#include "hydrogen-flow-engine.h"
|
| +#include "hydrogen-instructions.h"
|
| #include "hydrogen-removable-simulates.h"
|
|
|
| namespace v8 {
|
| namespace internal {
|
|
|
| -void HMergeRemovableSimulatesPhase::Run() {
|
| - ZoneList<HSimulate*> mergelist(2, zone());
|
| - for (int i = 0; i < graph()->blocks()->length(); ++i) {
|
| - HBasicBlock* block = graph()->blocks()->at(i);
|
| +class State : public ZoneObject {
|
| + public:
|
| + explicit State(Zone* zone)
|
| + : zone_(zone), mergelist_(2, zone), first_(true), mode_(NORMAL) { }
|
| +
|
| + State* Process(HInstruction* instr, Zone* zone) {
|
| + if (FLAG_trace_removable_simulates) {
|
| + PrintF("[State::Process %s #%d %s]\n",
|
| + mode_ == NORMAL ? "normal" : "collect",
|
| + instr->id(), instr->Mnemonic());
|
| + }
|
| + // Forward-merge "trains" of simulates after an instruction with observable
|
| + // side effects to keep live ranges short.
|
| + if (mode_ == COLLECT_CONSECUTIVE_SIMULATES) {
|
| + if (instr->IsSimulate()) {
|
| + HSimulate* current_simulate = HSimulate::cast(instr);
|
| + if (current_simulate->is_candidate_for_removal() &&
|
| + !current_simulate->ast_id().IsNone()) {
|
| + Remember(current_simulate);
|
| + return this;
|
| + }
|
| + }
|
| + FlushSimulates();
|
| + mode_ = NORMAL;
|
| + }
|
| + // Ensure there's a non-foldable HSimulate before an HEnterInlined to avoid
|
| + // folding across HEnterInlined.
|
| + ASSERT(!(instr->IsEnterInlined() &&
|
| + HSimulate::cast(instr->previous())->is_candidate_for_removal()));
|
| + if (instr->IsLeaveInlined() || instr->IsReturn()) {
|
| + // Never fold simulates from inlined environments into simulates in the
|
| + // outer environment. Simply remove all accumulated simulates without
|
| + // merging. This is safe because simulates after instructions with side
|
| + // effects are never added to the merge list. The same reasoning holds for
|
| + // return instructions.
|
| + RemoveSimulates();
|
| + return this;
|
| + }
|
| + if (instr->IsControlInstruction()) {
|
| + // Merge the accumulated simulates at the end of the block.
|
| + FlushSimulates();
|
| + return this;
|
| + }
|
| + // Skip the non-simulates and the first simulate.
|
| + if (!instr->IsSimulate()) return this;
|
| + if (first_) {
|
| + first_ = false;
|
| + return this;
|
| + }
|
| + HSimulate* current_simulate = HSimulate::cast(instr);
|
| + if (!current_simulate->is_candidate_for_removal()) {
|
| + Remember(current_simulate);
|
| + FlushSimulates();
|
| + } else if (current_simulate->ast_id().IsNone()) {
|
| + ASSERT(current_simulate->next()->IsEnterInlined());
|
| + FlushSimulates();
|
| + } else if (current_simulate->previous()->HasObservableSideEffects()) {
|
| + Remember(current_simulate);
|
| + mode_ = COLLECT_CONSECUTIVE_SIMULATES;
|
| + } else {
|
| + Remember(current_simulate);
|
| + }
|
| +
|
| + return this;
|
| + }
|
| +
|
| + static State* Merge(State* succ_state,
|
| + HBasicBlock* succ_block,
|
| + State* pred_state,
|
| + HBasicBlock* pred_block,
|
| + Zone* zone) {
|
| + if (FLAG_trace_removable_simulates) {
|
| + PrintF("[State::Merge predecessor block %d, successor block %d\n",
|
| + pred_block->block_id(), succ_block->block_id());
|
| + }
|
| + return pred_state;
|
| + }
|
| +
|
| + static State* Finish(State* state, HBasicBlock* block, Zone* zone) {
|
| + if (FLAG_trace_removable_simulates) {
|
| + PrintF("[State::Finish block %d]\n", block->block_id()); }
|
| // Make sure the merge list is empty at the start of a block.
|
| - ASSERT(mergelist.is_empty());
|
| + ASSERT(state->mergelist_.is_empty());
|
| // Nasty heuristic: Never remove the first simulate in a block. This
|
| // just so happens to have a beneficial effect on register allocation.
|
| - bool first = true;
|
| - for (HInstructionIterator it(block); !it.Done(); it.Advance()) {
|
| - HInstruction* current = it.Current();
|
| - if (current->IsEnterInlined()) {
|
| - // Ensure there's a non-foldable HSimulate before an HEnterInlined to
|
| - // avoid folding across HEnterInlined.
|
| - ASSERT(!HSimulate::cast(current->previous())->
|
| - is_candidate_for_removal());
|
| - }
|
| - if (current->IsLeaveInlined()) {
|
| - // Never fold simulates from inlined environments into simulates in the
|
| - // outer environment. Simply remove all accumulated simulates without
|
| - // merging. This is safe because simulates after instructions with side
|
| - // effects are never added to the merge list.
|
| - while (!mergelist.is_empty()) {
|
| - mergelist.RemoveLast()->DeleteAndReplaceWith(NULL);
|
| - }
|
| - continue;
|
| - }
|
| - if (current->IsReturn()) {
|
| - // Drop mergeable simulates in the list. This is safe because
|
| - // simulates after instructions with side effects are never added
|
| - // to the merge list.
|
| - while (!mergelist.is_empty()) {
|
| - mergelist.RemoveLast()->DeleteAndReplaceWith(NULL);
|
| - }
|
| - continue;
|
| - }
|
| - // Skip the non-simulates and the first simulate.
|
| - if (!current->IsSimulate()) continue;
|
| - if (first) {
|
| - first = false;
|
| - continue;
|
| - }
|
| - HSimulate* current_simulate = HSimulate::cast(current);
|
| - if (!current_simulate->is_candidate_for_removal()) {
|
| - current_simulate->MergeWith(&mergelist);
|
| - } else if (current_simulate->ast_id().IsNone()) {
|
| - ASSERT(current_simulate->next()->IsEnterInlined());
|
| - if (!mergelist.is_empty()) {
|
| - HSimulate* last = mergelist.RemoveLast();
|
| - last->MergeWith(&mergelist);
|
| - }
|
| - } else if (current_simulate->previous()->HasObservableSideEffects()) {
|
| - while (current_simulate->next()->IsSimulate()) {
|
| - it.Advance();
|
| - HSimulate* next_simulate = HSimulate::cast(it.Current());
|
| - if (next_simulate->ast_id().IsNone()) break;
|
| - mergelist.Add(current_simulate, zone());
|
| - current_simulate = next_simulate;
|
| - if (!current_simulate->is_candidate_for_removal()) break;
|
| - }
|
| - current_simulate->MergeWith(&mergelist);
|
| - } else {
|
| - // Accumulate this simulate for folding later on.
|
| - mergelist.Add(current_simulate, zone());
|
| - }
|
| + state->first_ = true;
|
| + return state;
|
| + }
|
| +
|
| + private:
|
| + enum Mode { NORMAL, COLLECT_CONSECUTIVE_SIMULATES };
|
| +
|
| + void Remember(HSimulate* sim) {
|
| + mergelist_.Add(sim, zone_);
|
| + }
|
| +
|
| + void FlushSimulates() {
|
| + if (!mergelist_.is_empty()) {
|
| + mergelist_.RemoveLast()->MergeWith(&mergelist_);
|
| }
|
| + }
|
|
|
| - if (!mergelist.is_empty()) {
|
| - // Merge the accumulated simulates at the end of the block.
|
| - HSimulate* last = mergelist.RemoveLast();
|
| - last->MergeWith(&mergelist);
|
| + void RemoveSimulates() {
|
| + while (!mergelist_.is_empty()) {
|
| + mergelist_.RemoveLast()->DeleteAndReplaceWith(NULL);
|
| }
|
| }
|
| +
|
| + Zone* zone_;
|
| + ZoneList<HSimulate*> mergelist_;
|
| + bool first_;
|
| + Mode mode_;
|
| +};
|
| +
|
| +
|
| +// We don't use effects here.
|
| +class Effects : public ZoneObject {
|
| + public:
|
| + explicit Effects(Zone* zone) { }
|
| + bool Disabled() { return true; }
|
| + void Process(HInstruction* instr, Zone* zone) { }
|
| + void Apply(State* state) { }
|
| + void Union(Effects* that, Zone* zone) { }
|
| +};
|
| +
|
| +
|
| +void HMergeRemovableSimulatesPhase::Run() {
|
| + HFlowEngine<State, Effects> engine(graph(), zone());
|
| + State* state = new(zone()) State(zone());
|
| + engine.AnalyzeDominatedBlocks(graph()->blocks()->at(0), state);
|
| }
|
|
|
| } } // namespace v8::internal
|
|
|