blob: 73d7a8e0583eb9c53946c33b80f54dc98948126f [file] [log] [blame]
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001// 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
9namespace v8 {
10namespace internal {
11
12class State : public ZoneObject {
13 public:
14 explicit State(Zone* zone)
15 : zone_(zone), mergelist_(2, zone), first_(true), mode_(NORMAL) { }
16
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 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -040056 if (instr->IsCapturedObject()) {
57 // Do not merge simulates across captured objects - captured objects
58 // change environments during environment replay, and such changes
59 // would not be reflected in the simulate.
60 FlushSimulates();
61 return this;
62 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000063 // Skip the non-simulates and the first simulate.
64 if (!instr->IsSimulate()) return this;
65 if (first_) {
66 first_ = false;
67 return this;
68 }
69 HSimulate* current_simulate = HSimulate::cast(instr);
70 if (!current_simulate->is_candidate_for_removal()) {
71 Remember(current_simulate);
72 FlushSimulates();
73 } else if (current_simulate->ast_id().IsNone()) {
74 DCHECK(current_simulate->next()->IsEnterInlined());
75 FlushSimulates();
76 } else if (current_simulate->previous()->HasObservableSideEffects()) {
77 Remember(current_simulate);
78 mode_ = COLLECT_CONSECUTIVE_SIMULATES;
79 } else {
80 Remember(current_simulate);
81 }
82
83 return this;
84 }
85
86 static State* Merge(State* succ_state,
87 HBasicBlock* succ_block,
88 State* pred_state,
89 HBasicBlock* pred_block,
90 Zone* zone) {
91 return (succ_state == NULL)
92 ? pred_state->Copy(succ_block, pred_block, zone)
93 : succ_state->Merge(succ_block, pred_state, pred_block, zone);
94 }
95
96 static State* Finish(State* state, HBasicBlock* block, Zone* zone) {
97 if (FLAG_trace_removable_simulates) {
98 PrintF("[preparing state %p for B%d]\n", reinterpret_cast<void*>(state),
99 block->block_id());
100 }
101 // For our current local analysis, we should not remember simulates across
102 // block boundaries.
103 DCHECK(!state->HasRememberedSimulates());
104 // Nasty heuristic: Never remove the first simulate in a block. This
105 // just so happens to have a beneficial effect on register allocation.
106 state->first_ = true;
107 return state;
108 }
109
110 private:
111 explicit State(const State& other)
112 : zone_(other.zone_),
113 mergelist_(other.mergelist_, other.zone_),
114 first_(other.first_),
115 mode_(other.mode_) { }
116
117 enum Mode { NORMAL, COLLECT_CONSECUTIVE_SIMULATES };
118
119 bool HasRememberedSimulates() const { return !mergelist_.is_empty(); }
120
121 void Remember(HSimulate* sim) {
122 mergelist_.Add(sim, zone_);
123 }
124
125 void FlushSimulates() {
126 if (HasRememberedSimulates()) {
127 mergelist_.RemoveLast()->MergeWith(&mergelist_);
128 }
129 }
130
131 void RemoveSimulates() {
132 while (HasRememberedSimulates()) {
133 mergelist_.RemoveLast()->DeleteAndReplaceWith(NULL);
134 }
135 }
136
137 State* Copy(HBasicBlock* succ_block, HBasicBlock* pred_block, Zone* zone) {
138 State* copy = new(zone) State(*this);
139 if (FLAG_trace_removable_simulates) {
140 PrintF("[copy state %p from B%d to new state %p for B%d]\n",
141 reinterpret_cast<void*>(this), pred_block->block_id(),
142 reinterpret_cast<void*>(copy), succ_block->block_id());
143 }
144 return copy;
145 }
146
147 State* Merge(HBasicBlock* succ_block,
148 State* pred_state,
149 HBasicBlock* pred_block,
150 Zone* zone) {
151 // For our current local analysis, we should not remember simulates across
152 // block boundaries.
153 DCHECK(!pred_state->HasRememberedSimulates());
154 DCHECK(!HasRememberedSimulates());
155 if (FLAG_trace_removable_simulates) {
156 PrintF("[merge state %p from B%d into %p for B%d]\n",
157 reinterpret_cast<void*>(pred_state), pred_block->block_id(),
158 reinterpret_cast<void*>(this), succ_block->block_id());
159 }
160 return this;
161 }
162
163 Zone* zone_;
164 ZoneList<HSimulate*> mergelist_;
165 bool first_;
166 Mode mode_;
167};
168
169
170// We don't use effects here.
171class Effects : public ZoneObject {
172 public:
173 explicit Effects(Zone* zone) { }
174 bool Disabled() { return true; }
175 void Process(HInstruction* instr, Zone* zone) { }
176 void Apply(State* state) { }
177 void Union(Effects* that, Zone* zone) { }
178};
179
180
181void HMergeRemovableSimulatesPhase::Run() {
182 HFlowEngine<State, Effects> engine(graph(), zone());
183 State* state = new(zone()) State(zone());
184 engine.AnalyzeDominatedBlocks(graph()->blocks()->at(0), state);
185}
186
187} } // namespace v8::internal