• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2013 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "src/hydrogen-flow-engine.h"
6 #include "src/hydrogen-instructions.h"
7 #include "src/hydrogen-removable-simulates.h"
8 
9 namespace v8 {
10 namespace internal {
11 
12 class State : public ZoneObject {
13  public:
State(Zone * zone)14   explicit State(Zone* zone)
15       : zone_(zone), mergelist_(2, zone), first_(true), mode_(NORMAL) { }
16 
Process(HInstruction * instr,Zone * zone)17   State* Process(HInstruction* instr, Zone* zone) {
18     if (FLAG_trace_removable_simulates) {
19       PrintF("[%s with state %p in B%d: #%d %s]\n",
20              mode_ == NORMAL ? "processing" : "collecting",
21              reinterpret_cast<void*>(this), instr->block()->block_id(),
22              instr->id(), instr->Mnemonic());
23     }
24     // Forward-merge "trains" of simulates after an instruction with observable
25     // side effects to keep live ranges short.
26     if (mode_ == COLLECT_CONSECUTIVE_SIMULATES) {
27       if (instr->IsSimulate()) {
28         HSimulate* current_simulate = HSimulate::cast(instr);
29         if (current_simulate->is_candidate_for_removal() &&
30             !current_simulate->ast_id().IsNone()) {
31           Remember(current_simulate);
32           return this;
33         }
34       }
35       FlushSimulates();
36       mode_ = NORMAL;
37     }
38     // Ensure there's a non-foldable HSimulate before an HEnterInlined to avoid
39     // folding across HEnterInlined.
40     DCHECK(!(instr->IsEnterInlined() &&
41              HSimulate::cast(instr->previous())->is_candidate_for_removal()));
42     if (instr->IsLeaveInlined() || instr->IsReturn()) {
43       // Never fold simulates from inlined environments into simulates in the
44       // outer environment. Simply remove all accumulated simulates without
45       // merging. This is safe because simulates after instructions with side
46       // effects are never added to the merge list. The same reasoning holds for
47       // return instructions.
48       RemoveSimulates();
49       return this;
50     }
51     if (instr->IsControlInstruction()) {
52       // Merge the accumulated simulates at the end of the block.
53       FlushSimulates();
54       return this;
55     }
56     // Skip the non-simulates and the first simulate.
57     if (!instr->IsSimulate()) return this;
58     if (first_) {
59       first_ = false;
60       return this;
61     }
62     HSimulate* current_simulate = HSimulate::cast(instr);
63     if (!current_simulate->is_candidate_for_removal()) {
64       Remember(current_simulate);
65       FlushSimulates();
66     } else if (current_simulate->ast_id().IsNone()) {
67       DCHECK(current_simulate->next()->IsEnterInlined());
68       FlushSimulates();
69     } else if (current_simulate->previous()->HasObservableSideEffects()) {
70       Remember(current_simulate);
71       mode_ = COLLECT_CONSECUTIVE_SIMULATES;
72     } else {
73       Remember(current_simulate);
74     }
75 
76     return this;
77   }
78 
Merge(State * succ_state,HBasicBlock * succ_block,State * pred_state,HBasicBlock * pred_block,Zone * zone)79   static State* Merge(State* succ_state,
80                       HBasicBlock* succ_block,
81                       State* pred_state,
82                       HBasicBlock* pred_block,
83                       Zone* zone) {
84     return (succ_state == NULL)
85         ? pred_state->Copy(succ_block, pred_block, zone)
86         : succ_state->Merge(succ_block, pred_state, pred_block, zone);
87   }
88 
Finish(State * state,HBasicBlock * block,Zone * zone)89   static State* Finish(State* state, HBasicBlock* block, Zone* zone) {
90     if (FLAG_trace_removable_simulates) {
91       PrintF("[preparing state %p for B%d]\n", reinterpret_cast<void*>(state),
92              block->block_id());
93     }
94     // For our current local analysis, we should not remember simulates across
95     // block boundaries.
96     DCHECK(!state->HasRememberedSimulates());
97     // Nasty heuristic: Never remove the first simulate in a block. This
98     // just so happens to have a beneficial effect on register allocation.
99     state->first_ = true;
100     return state;
101   }
102 
103  private:
State(const State & other)104   explicit State(const State& other)
105       : zone_(other.zone_),
106         mergelist_(other.mergelist_, other.zone_),
107         first_(other.first_),
108         mode_(other.mode_) { }
109 
110   enum Mode { NORMAL, COLLECT_CONSECUTIVE_SIMULATES };
111 
HasRememberedSimulates() const112   bool HasRememberedSimulates() const { return !mergelist_.is_empty(); }
113 
Remember(HSimulate * sim)114   void Remember(HSimulate* sim) {
115     mergelist_.Add(sim, zone_);
116   }
117 
FlushSimulates()118   void FlushSimulates() {
119     if (HasRememberedSimulates()) {
120       mergelist_.RemoveLast()->MergeWith(&mergelist_);
121     }
122   }
123 
RemoveSimulates()124   void RemoveSimulates() {
125     while (HasRememberedSimulates()) {
126       mergelist_.RemoveLast()->DeleteAndReplaceWith(NULL);
127     }
128   }
129 
Copy(HBasicBlock * succ_block,HBasicBlock * pred_block,Zone * zone)130   State* Copy(HBasicBlock* succ_block, HBasicBlock* pred_block, Zone* zone) {
131     State* copy = new(zone) State(*this);
132     if (FLAG_trace_removable_simulates) {
133       PrintF("[copy state %p from B%d to new state %p for B%d]\n",
134              reinterpret_cast<void*>(this), pred_block->block_id(),
135              reinterpret_cast<void*>(copy), succ_block->block_id());
136     }
137     return copy;
138   }
139 
Merge(HBasicBlock * succ_block,State * pred_state,HBasicBlock * pred_block,Zone * zone)140   State* Merge(HBasicBlock* succ_block,
141                State* pred_state,
142                HBasicBlock* pred_block,
143                Zone* zone) {
144     // For our current local analysis, we should not remember simulates across
145     // block boundaries.
146     DCHECK(!pred_state->HasRememberedSimulates());
147     DCHECK(!HasRememberedSimulates());
148     if (FLAG_trace_removable_simulates) {
149       PrintF("[merge state %p from B%d into %p for B%d]\n",
150              reinterpret_cast<void*>(pred_state), pred_block->block_id(),
151              reinterpret_cast<void*>(this), succ_block->block_id());
152     }
153     return this;
154   }
155 
156   Zone* zone_;
157   ZoneList<HSimulate*> mergelist_;
158   bool first_;
159   Mode mode_;
160 };
161 
162 
163 // We don't use effects here.
164 class Effects : public ZoneObject {
165  public:
Effects(Zone * zone)166   explicit Effects(Zone* zone) { }
Disabled()167   bool Disabled() { return true; }
Process(HInstruction * instr,Zone * zone)168   void Process(HInstruction* instr, Zone* zone) { }
Apply(State * state)169   void Apply(State* state) { }
Union(Effects * that,Zone * zone)170   void Union(Effects* that, Zone* zone) { }
171 };
172 
173 
Run()174 void HMergeRemovableSimulatesPhase::Run() {
175   HFlowEngine<State, Effects> engine(graph(), zone());
176   State* state = new(zone()) State(zone());
177   engine.AnalyzeDominatedBlocks(graph()->blocks()->at(0), state);
178 }
179 
180 } }  // namespace v8::internal
181