5 #include "src/compiler/loop-variable-optimizer.h" 7 #include "src/compiler/common-operator.h" 8 #include "src/compiler/graph.h" 9 #include "src/compiler/node-marker.h" 10 #include "src/compiler/node-properties.h" 11 #include "src/compiler/node.h" 12 #include "src/zone/zone-containers.h" 13 #include "src/zone/zone.h" 22 if (FLAG_trace_turbo_loop) PrintF(__VA_ARGS__); \ 25 LoopVariableOptimizer::LoopVariableOptimizer(Graph* graph,
26 CommonOperatorBuilder* common,
31 limits_(graph->NodeCount(), zone),
32 reduced_(graph->NodeCount(), zone),
33 induction_vars_(zone) {}
35 void LoopVariableOptimizer::Run() {
36 ZoneQueue<Node*> queue(zone());
37 queue.push(graph()->start());
38 NodeMarker<bool> queued(graph(), 2);
39 while (!queue.empty()) {
40 Node* node = queue.front();
42 queued.Set(node,
false);
44 DCHECK(!reduced_.Get(node));
45 bool all_inputs_visited =
true;
46 int inputs_end = (node->opcode() == IrOpcode::kLoop)
48 : node->op()->ControlInputCount();
49 for (
int i = 0;
i < inputs_end;
i++) {
50 if (!reduced_.Get(NodeProperties::GetControlInput(node,
i))) {
51 all_inputs_visited =
false;
55 if (!all_inputs_visited)
continue;
58 reduced_.Set(node,
true);
61 for (Edge edge : node->use_edges()) {
62 if (NodeProperties::IsControlEdge(edge) &&
63 edge.from()->op()->ControlOutputCount() > 0) {
64 Node* use = edge.from();
65 if (use->opcode() == IrOpcode::kLoop &&
66 edge.index() != kAssumedLoopEntryIndex) {
67 VisitBackedge(node, use);
68 }
else if (!queued.Get(use)) {
70 queued.Set(use,
true);
77 void InductionVariable::AddUpperBound(Node* bound,
78 InductionVariable::ConstraintKind kind) {
79 if (FLAG_trace_turbo_loop) {
80 StdoutStream{} <<
"New upper bound for " << phi()->id() <<
" (loop " 81 << NodeProperties::GetControlInput(phi())->id()
82 <<
"): " << *bound << std::endl;
84 upper_bounds_.push_back(Bound(bound, kind));
87 void InductionVariable::AddLowerBound(Node* bound,
88 InductionVariable::ConstraintKind kind) {
89 if (FLAG_trace_turbo_loop) {
90 StdoutStream{} <<
"New lower bound for " << phi()->id() <<
" (loop " 91 << NodeProperties::GetControlInput(phi())->id()
94 lower_bounds_.push_back(Bound(bound, kind));
97 void LoopVariableOptimizer::VisitBackedge(Node* from, Node* loop) {
98 if (loop->op()->ControlInputCount() != 2)
return;
102 for (Constraint constraint : limits_.Get(from)) {
103 if (constraint.left->opcode() == IrOpcode::kPhi &&
104 NodeProperties::GetControlInput(constraint.left) == loop) {
105 auto var = induction_vars_.find(constraint.left->id());
106 if (var != induction_vars_.end()) {
107 var->second->AddUpperBound(constraint.right, constraint.kind);
110 if (constraint.right->opcode() == IrOpcode::kPhi &&
111 NodeProperties::GetControlInput(constraint.right) == loop) {
112 auto var = induction_vars_.find(constraint.right->id());
113 if (var != induction_vars_.end()) {
114 var->second->AddLowerBound(constraint.left, constraint.kind);
120 void LoopVariableOptimizer::VisitNode(Node* node) {
121 switch (node->opcode()) {
122 case IrOpcode::kMerge:
123 return VisitMerge(node);
124 case IrOpcode::kLoop:
125 return VisitLoop(node);
126 case IrOpcode::kIfFalse:
127 return VisitIf(node,
false);
128 case IrOpcode::kIfTrue:
129 return VisitIf(node,
true);
130 case IrOpcode::kStart:
131 return VisitStart(node);
132 case IrOpcode::kLoopExit:
133 return VisitLoopExit(node);
135 return VisitOtherControl(node);
139 void LoopVariableOptimizer::VisitMerge(Node* node) {
141 VariableLimits merged = limits_.Get(node->InputAt(0));
142 for (
int i = 1;
i < node->InputCount();
i++) {
143 merged.ResetToCommonAncestor(limits_.Get(node->InputAt(
i)));
145 limits_.Set(node, merged);
148 void LoopVariableOptimizer::VisitLoop(Node* node) {
149 DetectInductionVariables(node);
151 return TakeConditionsFromFirstControl(node);
154 void LoopVariableOptimizer::VisitIf(Node* node,
bool polarity) {
155 Node* branch = node->InputAt(0);
156 Node* cond = branch->InputAt(0);
157 VariableLimits limits = limits_.Get(branch);
159 switch (cond->opcode()) {
160 case IrOpcode::kJSLessThan:
161 case IrOpcode::kNumberLessThan:
162 case IrOpcode::kSpeculativeNumberLessThan:
163 AddCmpToLimits(&limits, cond, InductionVariable::kStrict, polarity);
165 case IrOpcode::kJSGreaterThan:
166 AddCmpToLimits(&limits, cond, InductionVariable::kNonStrict, !polarity);
168 case IrOpcode::kJSLessThanOrEqual:
169 case IrOpcode::kNumberLessThanOrEqual:
170 case IrOpcode::kSpeculativeNumberLessThanOrEqual:
171 AddCmpToLimits(&limits, cond, InductionVariable::kNonStrict, polarity);
173 case IrOpcode::kJSGreaterThanOrEqual:
174 AddCmpToLimits(&limits, cond, InductionVariable::kStrict, !polarity);
179 limits_.Set(node, limits);
182 void LoopVariableOptimizer::AddCmpToLimits(
183 VariableLimits* limits, Node* node, InductionVariable::ConstraintKind kind,
185 Node* left = node->InputAt(0);
186 Node* right = node->InputAt(1);
187 if (FindInductionVariable(left) || FindInductionVariable(right)) {
189 limits->PushFront(Constraint{left, kind, right}, zone());
191 kind = (kind == InductionVariable::kStrict)
192 ? InductionVariable::kNonStrict
193 : InductionVariable::kStrict;
194 limits->PushFront(Constraint{right, kind, left}, zone());
199 void LoopVariableOptimizer::VisitStart(Node* node) { limits_.Set(node, {}); }
201 void LoopVariableOptimizer::VisitLoopExit(Node* node) {
202 return TakeConditionsFromFirstControl(node);
205 void LoopVariableOptimizer::VisitOtherControl(Node* node) {
206 DCHECK_EQ(1, node->op()->ControlInputCount());
207 return TakeConditionsFromFirstControl(node);
210 void LoopVariableOptimizer::TakeConditionsFromFirstControl(Node* node) {
211 limits_.Set(node, limits_.Get(NodeProperties::GetControlInput(node, 0)));
214 const InductionVariable* LoopVariableOptimizer::FindInductionVariable(
216 auto var = induction_vars_.find(node->id());
217 if (var != induction_vars_.end()) {
223 InductionVariable* LoopVariableOptimizer::TryGetInductionVariable(Node* phi) {
224 DCHECK_EQ(2, phi->op()->ValueInputCount());
225 Node* loop = NodeProperties::GetControlInput(phi);
226 DCHECK_EQ(IrOpcode::kLoop, loop->opcode());
227 Node* initial = phi->InputAt(0);
228 Node* arith = phi->InputAt(1);
229 InductionVariable::ArithmeticType arithmeticType;
230 if (arith->opcode() == IrOpcode::kJSAdd ||
231 arith->opcode() == IrOpcode::kNumberAdd ||
232 arith->opcode() == IrOpcode::kSpeculativeNumberAdd ||
233 arith->opcode() == IrOpcode::kSpeculativeSafeIntegerAdd) {
234 arithmeticType = InductionVariable::ArithmeticType::kAddition;
235 }
else if (arith->opcode() == IrOpcode::kJSSubtract ||
236 arith->opcode() == IrOpcode::kNumberSubtract ||
237 arith->opcode() == IrOpcode::kSpeculativeNumberSubtract ||
238 arith->opcode() == IrOpcode::kSpeculativeSafeIntegerSubtract) {
239 arithmeticType = InductionVariable::ArithmeticType::kSubtraction;
245 Node* input = arith->InputAt(0);
246 if (input->opcode() == IrOpcode::kSpeculativeToNumber ||
247 input->opcode() == IrOpcode::kJSToNumber ||
248 input->opcode() == IrOpcode::kJSToNumberConvertBigInt) {
249 input = input->InputAt(0);
251 if (input != phi)
return nullptr;
253 Node* effect_phi =
nullptr;
254 for (Node* use : loop->uses()) {
255 if (use->opcode() == IrOpcode::kEffectPhi) {
256 DCHECK_NULL(effect_phi);
260 if (!effect_phi)
return nullptr;
262 Node* incr = arith->InputAt(1);
263 return new (zone()) InductionVariable(phi, effect_phi, arith, incr, initial,
264 zone(), arithmeticType);
267 void LoopVariableOptimizer::DetectInductionVariables(Node* loop) {
268 if (loop->op()->ControlInputCount() != 2)
return;
269 TRACE(
"Loop variables for loop %i:", loop->id());
270 for (Edge edge : loop->use_edges()) {
271 if (NodeProperties::IsControlEdge(edge) &&
272 edge.from()->opcode() == IrOpcode::kPhi) {
273 Node* phi = edge.from();
274 InductionVariable* induction_var = TryGetInductionVariable(phi);
276 induction_vars_[phi->id()] = induction_var;
277 TRACE(
" %i", induction_var->phi()->id());
284 void LoopVariableOptimizer::ChangeToInductionVariablePhis() {
285 for (
auto entry : induction_vars_) {
288 InductionVariable* induction_var = entry.second;
289 DCHECK_EQ(MachineRepresentation::kTagged,
290 PhiRepresentationOf(induction_var->phi()->op()));
291 if (induction_var->upper_bounds().size() == 0 &&
292 induction_var->lower_bounds().size() == 0) {
296 induction_var->phi()->InsertInput(graph()->zone(),
297 induction_var->phi()->InputCount() - 1,
298 induction_var->increment());
300 for (
auto bound : induction_var->lower_bounds()) {
301 induction_var->phi()->InsertInput(
302 graph()->zone(), induction_var->phi()->InputCount() - 1, bound.bound);
304 for (
auto bound : induction_var->upper_bounds()) {
305 induction_var->phi()->InsertInput(
306 graph()->zone(), induction_var->phi()->InputCount() - 1, bound.bound);
308 NodeProperties::ChangeOp(
309 induction_var->phi(),
310 common()->InductionVariablePhi(induction_var->phi()->InputCount() - 1));
314 void LoopVariableOptimizer::ChangeToPhisAndInsertGuards() {
315 for (
auto entry : induction_vars_) {
316 InductionVariable* induction_var = entry.second;
317 if (induction_var->phi()->opcode() == IrOpcode::kInductionVariablePhi) {
320 Node* control = NodeProperties::GetControlInput(induction_var->phi());
321 DCHECK_EQ(value_count, control->op()->ControlInputCount());
322 induction_var->phi()->TrimInputCount(value_count + 1);
323 induction_var->phi()->ReplaceInput(value_count, control);
324 NodeProperties::ChangeOp(
325 induction_var->phi(),
326 common()->Phi(MachineRepresentation::kTagged, value_count));
330 Node* backedge_value = induction_var->phi()->InputAt(1);
331 Type backedge_type = NodeProperties::GetType(backedge_value);
332 Type phi_type = NodeProperties::GetType(induction_var->phi());
333 if (!backedge_type.Is(phi_type)) {
334 Node* loop = NodeProperties::GetControlInput(induction_var->phi());
335 Node* backedge_control = loop->InputAt(1);
336 Node* backedge_effect =
337 NodeProperties::GetEffectInput(induction_var->effect_phi(), 1);
339 graph()->NewNode(common()->TypeGuard(phi_type), backedge_value,
340 backedge_effect, backedge_control);
341 induction_var->effect_phi()->ReplaceInput(1, rename);
342 induction_var->phi()->ReplaceInput(1, rename);