blob: 1ff6bbeccf3c053bf69702f2ea21c5ca9424155c [file] [log] [blame]
Aart Bik30efb4e2015-07-30 12:14:31 -07001/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "induction_var_analysis.h"
Aart Bik22af3be2015-09-10 12:50:58 -070018#include "induction_var_range.h"
Aart Bik30efb4e2015-07-30 12:14:31 -070019
20namespace art {
21
22/**
23 * Returns true if instruction is invariant within the given loop.
24 */
25static bool IsLoopInvariant(HLoopInformation* loop, HInstruction* instruction) {
26 HLoopInformation* other_loop = instruction->GetBlock()->GetLoopInformation();
27 if (other_loop != loop) {
28 // If instruction does not occur in same loop, it is invariant
29 // if it appears in an outer loop (including no loop at all).
30 return other_loop == nullptr || loop->IsIn(*other_loop);
31 }
32 return false;
33}
34
35/**
Aart Bik22af3be2015-09-10 12:50:58 -070036 * Since graph traversal may enter a SCC at any position, an initial representation may be rotated,
37 * along dependences, viz. any of (a, b, c, d), (d, a, b, c) (c, d, a, b), (b, c, d, a) assuming
38 * a chain of dependences (mutual independent items may occur in arbitrary order). For proper
39 * classification, the lexicographically first entry-phi is rotated to the front.
40 */
41static void RotateEntryPhiFirst(HLoopInformation* loop,
42 ArenaVector<HInstruction*>* scc,
43 ArenaVector<HInstruction*>* new_scc) {
44 // Find very first entry-phi.
45 const HInstructionList& phis = loop->GetHeader()->GetPhis();
46 HInstruction* phi = nullptr;
47 size_t phi_pos = -1;
48 const size_t size = scc->size();
49 for (size_t i = 0; i < size; i++) {
Aart Bikf475bee2015-09-16 12:50:25 -070050 HInstruction* other = scc->at(i);
51 if (other->IsLoopHeaderPhi() && (phi == nullptr || phis.FoundBefore(other, phi))) {
52 phi = other;
Aart Bik22af3be2015-09-10 12:50:58 -070053 phi_pos = i;
54 }
55 }
56
57 // If found, bring that entry-phi to front.
58 if (phi != nullptr) {
59 new_scc->clear();
60 for (size_t i = 0; i < size; i++) {
61 DCHECK_LT(phi_pos, size);
62 new_scc->push_back(scc->at(phi_pos));
63 if (++phi_pos >= size) phi_pos = 0;
64 }
65 DCHECK_EQ(size, new_scc->size());
66 scc->swap(*new_scc);
67 }
68}
69
Aart Bik30efb4e2015-07-30 12:14:31 -070070//
71// Class methods.
72//
73
74HInductionVarAnalysis::HInductionVarAnalysis(HGraph* graph)
75 : HOptimization(graph, kInductionPassName),
76 global_depth_(0),
77 stack_(graph->GetArena()->Adapter()),
78 scc_(graph->GetArena()->Adapter()),
Aart Bike609b7c2015-08-27 13:46:58 -070079 map_(std::less<HInstruction*>(), graph->GetArena()->Adapter()),
80 cycle_(std::less<HInstruction*>(), graph->GetArena()->Adapter()),
81 induction_(std::less<HLoopInformation*>(), graph->GetArena()->Adapter()) {
Aart Bik30efb4e2015-07-30 12:14:31 -070082}
83
84void HInductionVarAnalysis::Run() {
Aart Bike609b7c2015-08-27 13:46:58 -070085 // Detects sequence variables (generalized induction variables) during an inner-loop-first
86 // traversal of all loops using Gerlek's algorithm. The order is only relevant if outer
87 // loops would use induction information of inner loops (not currently done).
Aart Bik30efb4e2015-07-30 12:14:31 -070088 for (HPostOrderIterator it_graph(*graph_); !it_graph.Done(); it_graph.Advance()) {
89 HBasicBlock* graph_block = it_graph.Current();
90 if (graph_block->IsLoopHeader()) {
91 VisitLoop(graph_block->GetLoopInformation());
92 }
93 }
94}
95
96void HInductionVarAnalysis::VisitLoop(HLoopInformation* loop) {
97 // Find strongly connected components (SSCs) in the SSA graph of this loop using Tarjan's
98 // algorithm. Due to the descendant-first nature, classification happens "on-demand".
99 global_depth_ = 0;
Aart Bike609b7c2015-08-27 13:46:58 -0700100 DCHECK(stack_.empty());
Aart Bik30efb4e2015-07-30 12:14:31 -0700101 map_.clear();
102
103 for (HBlocksInLoopIterator it_loop(*loop); !it_loop.Done(); it_loop.Advance()) {
104 HBasicBlock* loop_block = it_loop.Current();
Aart Bike609b7c2015-08-27 13:46:58 -0700105 DCHECK(loop_block->IsInLoop());
Aart Bik30efb4e2015-07-30 12:14:31 -0700106 if (loop_block->GetLoopInformation() != loop) {
107 continue; // Inner loops already visited.
108 }
109 // Visit phi-operations and instructions.
110 for (HInstructionIterator it(loop_block->GetPhis()); !it.Done(); it.Advance()) {
111 HInstruction* instruction = it.Current();
Aart Bike609b7c2015-08-27 13:46:58 -0700112 if (!IsVisitedNode(instruction)) {
Aart Bik30efb4e2015-07-30 12:14:31 -0700113 VisitNode(loop, instruction);
114 }
115 }
116 for (HInstructionIterator it(loop_block->GetInstructions()); !it.Done(); it.Advance()) {
117 HInstruction* instruction = it.Current();
Aart Bike609b7c2015-08-27 13:46:58 -0700118 if (!IsVisitedNode(instruction)) {
Aart Bik30efb4e2015-07-30 12:14:31 -0700119 VisitNode(loop, instruction);
120 }
121 }
122 }
123
Aart Bike609b7c2015-08-27 13:46:58 -0700124 DCHECK(stack_.empty());
Aart Bik30efb4e2015-07-30 12:14:31 -0700125 map_.clear();
Aart Bikd14c5952015-09-08 15:25:15 -0700126
127 // Determine the loop's trip count.
128 VisitControl(loop);
Aart Bik30efb4e2015-07-30 12:14:31 -0700129}
130
131void HInductionVarAnalysis::VisitNode(HLoopInformation* loop, HInstruction* instruction) {
Aart Bik30efb4e2015-07-30 12:14:31 -0700132 const uint32_t d1 = ++global_depth_;
Aart Bike609b7c2015-08-27 13:46:58 -0700133 map_.Put(instruction, NodeInfo(d1));
Aart Bik30efb4e2015-07-30 12:14:31 -0700134 stack_.push_back(instruction);
135
136 // Visit all descendants.
137 uint32_t low = d1;
138 for (size_t i = 0, count = instruction->InputCount(); i < count; ++i) {
139 low = std::min(low, VisitDescendant(loop, instruction->InputAt(i)));
140 }
141
142 // Lower or found SCC?
143 if (low < d1) {
Aart Bike609b7c2015-08-27 13:46:58 -0700144 map_.find(instruction)->second.depth = low;
Aart Bik30efb4e2015-07-30 12:14:31 -0700145 } else {
146 scc_.clear();
147 cycle_.clear();
148
149 // Pop the stack to build the SCC for classification.
150 while (!stack_.empty()) {
151 HInstruction* x = stack_.back();
152 scc_.push_back(x);
153 stack_.pop_back();
Aart Bike609b7c2015-08-27 13:46:58 -0700154 map_.find(x)->second.done = true;
Aart Bik30efb4e2015-07-30 12:14:31 -0700155 if (x == instruction) {
156 break;
157 }
158 }
159
160 // Classify the SCC.
Aart Bikf475bee2015-09-16 12:50:25 -0700161 if (scc_.size() == 1 && !scc_[0]->IsLoopHeaderPhi()) {
Aart Bik30efb4e2015-07-30 12:14:31 -0700162 ClassifyTrivial(loop, scc_[0]);
163 } else {
164 ClassifyNonTrivial(loop);
165 }
166
167 scc_.clear();
168 cycle_.clear();
169 }
170}
171
172uint32_t HInductionVarAnalysis::VisitDescendant(HLoopInformation* loop, HInstruction* instruction) {
173 // If the definition is either outside the loop (loop invariant entry value)
174 // or assigned in inner loop (inner exit value), the traversal stops.
175 HLoopInformation* otherLoop = instruction->GetBlock()->GetLoopInformation();
176 if (otherLoop != loop) {
177 return global_depth_;
178 }
179
180 // Inspect descendant node.
Aart Bike609b7c2015-08-27 13:46:58 -0700181 if (!IsVisitedNode(instruction)) {
Aart Bik30efb4e2015-07-30 12:14:31 -0700182 VisitNode(loop, instruction);
Aart Bike609b7c2015-08-27 13:46:58 -0700183 return map_.find(instruction)->second.depth;
Aart Bik30efb4e2015-07-30 12:14:31 -0700184 } else {
Aart Bike609b7c2015-08-27 13:46:58 -0700185 auto it = map_.find(instruction);
Aart Bik30efb4e2015-07-30 12:14:31 -0700186 return it->second.done ? global_depth_ : it->second.depth;
187 }
188}
189
190void HInductionVarAnalysis::ClassifyTrivial(HLoopInformation* loop, HInstruction* instruction) {
191 InductionInfo* info = nullptr;
192 if (instruction->IsPhi()) {
Aart Bikf475bee2015-09-16 12:50:25 -0700193 info = TransferPhi(loop, instruction, /* input_index */ 0);
Aart Bik30efb4e2015-07-30 12:14:31 -0700194 } else if (instruction->IsAdd()) {
195 info = TransferAddSub(LookupInfo(loop, instruction->InputAt(0)),
196 LookupInfo(loop, instruction->InputAt(1)), kAdd);
197 } else if (instruction->IsSub()) {
198 info = TransferAddSub(LookupInfo(loop, instruction->InputAt(0)),
199 LookupInfo(loop, instruction->InputAt(1)), kSub);
200 } else if (instruction->IsMul()) {
201 info = TransferMul(LookupInfo(loop, instruction->InputAt(0)),
202 LookupInfo(loop, instruction->InputAt(1)));
Aart Bike609b7c2015-08-27 13:46:58 -0700203 } else if (instruction->IsShl()) {
204 info = TransferShl(LookupInfo(loop, instruction->InputAt(0)),
205 LookupInfo(loop, instruction->InputAt(1)),
206 instruction->InputAt(0)->GetType());
Aart Bik30efb4e2015-07-30 12:14:31 -0700207 } else if (instruction->IsNeg()) {
208 info = TransferNeg(LookupInfo(loop, instruction->InputAt(0)));
Aart Bike609b7c2015-08-27 13:46:58 -0700209 } else if (instruction->IsBoundsCheck()) {
210 info = LookupInfo(loop, instruction->InputAt(0)); // Pass-through.
211 } else if (instruction->IsTypeConversion()) {
212 HTypeConversion* conversion = instruction->AsTypeConversion();
213 // TODO: accept different conversion scenarios.
214 if (conversion->GetResultType() == conversion->GetInputType()) {
215 info = LookupInfo(loop, conversion->GetInput());
216 }
Aart Bik30efb4e2015-07-30 12:14:31 -0700217 }
218
219 // Successfully classified?
220 if (info != nullptr) {
221 AssignInfo(loop, instruction, info);
222 }
223}
224
225void HInductionVarAnalysis::ClassifyNonTrivial(HLoopInformation* loop) {
226 const size_t size = scc_.size();
Aart Bike609b7c2015-08-27 13:46:58 -0700227 DCHECK_GE(size, 1u);
Aart Bik22af3be2015-09-10 12:50:58 -0700228
229 // Rotate proper entry-phi to front.
230 if (size > 1) {
231 ArenaVector<HInstruction*> other(graph_->GetArena()->Adapter());
232 RotateEntryPhiFirst(loop, &scc_, &other);
233 }
234
Aart Bikf475bee2015-09-16 12:50:25 -0700235 // Analyze from entry-phi onwards.
Aart Bik22af3be2015-09-10 12:50:58 -0700236 HInstruction* phi = scc_[0];
Aart Bikf475bee2015-09-16 12:50:25 -0700237 if (!phi->IsLoopHeaderPhi()) {
Aart Bik30efb4e2015-07-30 12:14:31 -0700238 return;
239 }
Aart Bikf475bee2015-09-16 12:50:25 -0700240
241 // External link should be loop invariant.
242 InductionInfo* initial = LookupInfo(loop, phi->InputAt(0));
Aart Bik30efb4e2015-07-30 12:14:31 -0700243 if (initial == nullptr || initial->induction_class != kInvariant) {
244 return;
245 }
246
Aart Bikf475bee2015-09-16 12:50:25 -0700247 // Singleton is wrap-around induction if all internal links have the same meaning.
Aart Bik30efb4e2015-07-30 12:14:31 -0700248 if (size == 1) {
Aart Bikf475bee2015-09-16 12:50:25 -0700249 InductionInfo* update = TransferPhi(loop, phi, /* input_index */ 1);
Aart Bik30efb4e2015-07-30 12:14:31 -0700250 if (update != nullptr) {
Aart Bik471a2032015-09-04 18:22:11 -0700251 AssignInfo(loop, phi, CreateInduction(kWrapAround, initial, update));
Aart Bik30efb4e2015-07-30 12:14:31 -0700252 }
253 return;
254 }
255
256 // Inspect remainder of the cycle that resides in scc_. The cycle_ mapping assigns
Aart Bike609b7c2015-08-27 13:46:58 -0700257 // temporary meaning to its nodes, seeded from the phi instruction and back.
Aart Bik22af3be2015-09-10 12:50:58 -0700258 for (size_t i = 1; i < size; i++) {
Aart Bike609b7c2015-08-27 13:46:58 -0700259 HInstruction* instruction = scc_[i];
Aart Bik30efb4e2015-07-30 12:14:31 -0700260 InductionInfo* update = nullptr;
Aart Bike609b7c2015-08-27 13:46:58 -0700261 if (instruction->IsPhi()) {
Aart Bikf475bee2015-09-16 12:50:25 -0700262 update = SolvePhiAllInputs(loop, phi, instruction);
Aart Bike609b7c2015-08-27 13:46:58 -0700263 } else if (instruction->IsAdd()) {
264 update = SolveAddSub(
265 loop, phi, instruction, instruction->InputAt(0), instruction->InputAt(1), kAdd, true);
266 } else if (instruction->IsSub()) {
267 update = SolveAddSub(
268 loop, phi, instruction, instruction->InputAt(0), instruction->InputAt(1), kSub, true);
Aart Bik30efb4e2015-07-30 12:14:31 -0700269 }
270 if (update == nullptr) {
271 return;
272 }
Aart Bike609b7c2015-08-27 13:46:58 -0700273 cycle_.Put(instruction, update);
Aart Bik30efb4e2015-07-30 12:14:31 -0700274 }
275
Aart Bikf475bee2015-09-16 12:50:25 -0700276 // Success if all internal links received the same temporary meaning.
277 InductionInfo* induction = SolvePhi(phi, /* input_index */ 1);
278 if (induction != nullptr) {
Aart Bike609b7c2015-08-27 13:46:58 -0700279 switch (induction->induction_class) {
280 case kInvariant:
Aart Bik22af3be2015-09-10 12:50:58 -0700281 // Classify first phi and then the rest of the cycle "on-demand".
282 // Statements are scanned in order.
Aart Bik471a2032015-09-04 18:22:11 -0700283 AssignInfo(loop, phi, CreateInduction(kLinear, induction, initial));
Aart Bik22af3be2015-09-10 12:50:58 -0700284 for (size_t i = 1; i < size; i++) {
Aart Bike609b7c2015-08-27 13:46:58 -0700285 ClassifyTrivial(loop, scc_[i]);
286 }
287 break;
288 case kPeriodic:
Aart Bik22af3be2015-09-10 12:50:58 -0700289 // Classify all elements in the cycle with the found periodic induction while
290 // rotating each first element to the end. Lastly, phi is classified.
291 // Statements are scanned in reverse order.
292 for (size_t i = size - 1; i >= 1; i--) {
293 AssignInfo(loop, scc_[i], induction);
Aart Bike609b7c2015-08-27 13:46:58 -0700294 induction = RotatePeriodicInduction(induction->op_b, induction->op_a);
295 }
296 AssignInfo(loop, phi, induction);
297 break;
298 default:
299 break;
Aart Bik30efb4e2015-07-30 12:14:31 -0700300 }
301 }
302}
303
Aart Bike609b7c2015-08-27 13:46:58 -0700304HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::RotatePeriodicInduction(
305 InductionInfo* induction,
306 InductionInfo* last) {
307 // Rotates a periodic induction of the form
308 // (a, b, c, d, e)
309 // into
310 // (b, c, d, e, a)
311 // in preparation of assigning this to the previous variable in the sequence.
312 if (induction->induction_class == kInvariant) {
Aart Bik471a2032015-09-04 18:22:11 -0700313 return CreateInduction(kPeriodic, induction, last);
Aart Bike609b7c2015-08-27 13:46:58 -0700314 }
Aart Bik471a2032015-09-04 18:22:11 -0700315 return CreateInduction(kPeriodic, induction->op_a, RotatePeriodicInduction(induction->op_b, last));
Aart Bike609b7c2015-08-27 13:46:58 -0700316}
317
Aart Bikf475bee2015-09-16 12:50:25 -0700318HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::TransferPhi(HLoopInformation* loop,
319 HInstruction* phi,
320 size_t input_index) {
321 // Match all phi inputs from input_index onwards exactly.
322 const size_t count = phi->InputCount();
323 DCHECK_LT(input_index, count);
324 InductionInfo* a = LookupInfo(loop, phi->InputAt(input_index));
325 for (size_t i = input_index + 1; i < count; i++) {
326 InductionInfo* b = LookupInfo(loop, phi->InputAt(i));
327 if (!InductionEqual(a, b)) {
328 return nullptr;
329 }
Aart Bik30efb4e2015-07-30 12:14:31 -0700330 }
Aart Bikf475bee2015-09-16 12:50:25 -0700331 return a;
Aart Bik30efb4e2015-07-30 12:14:31 -0700332}
333
334HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::TransferAddSub(InductionInfo* a,
335 InductionInfo* b,
336 InductionOp op) {
Aart Bike609b7c2015-08-27 13:46:58 -0700337 // Transfer over an addition or subtraction: any invariant, linear, wrap-around, or periodic
338 // can be combined with an invariant to yield a similar result. Even two linear inputs can
339 // be combined. All other combinations fail, however.
Aart Bik30efb4e2015-07-30 12:14:31 -0700340 if (a != nullptr && b != nullptr) {
341 if (a->induction_class == kInvariant && b->induction_class == kInvariant) {
Aart Bik471a2032015-09-04 18:22:11 -0700342 return CreateInvariantOp(op, a, b);
Aart Bik30efb4e2015-07-30 12:14:31 -0700343 } else if (a->induction_class == kLinear && b->induction_class == kLinear) {
Aart Bik471a2032015-09-04 18:22:11 -0700344 return CreateInduction(
Aart Bike609b7c2015-08-27 13:46:58 -0700345 kLinear, TransferAddSub(a->op_a, b->op_a, op), TransferAddSub(a->op_b, b->op_b, op));
346 } else if (a->induction_class == kInvariant) {
347 InductionInfo* new_a = b->op_a;
348 InductionInfo* new_b = TransferAddSub(a, b->op_b, op);
349 if (b->induction_class != kLinear) {
350 DCHECK(b->induction_class == kWrapAround || b->induction_class == kPeriodic);
351 new_a = TransferAddSub(a, new_a, op);
352 } else if (op == kSub) { // Negation required.
353 new_a = TransferNeg(new_a);
354 }
Aart Bik471a2032015-09-04 18:22:11 -0700355 return CreateInduction(b->induction_class, new_a, new_b);
Aart Bike609b7c2015-08-27 13:46:58 -0700356 } else if (b->induction_class == kInvariant) {
357 InductionInfo* new_a = a->op_a;
358 InductionInfo* new_b = TransferAddSub(a->op_b, b, op);
359 if (a->induction_class != kLinear) {
360 DCHECK(a->induction_class == kWrapAround || a->induction_class == kPeriodic);
361 new_a = TransferAddSub(new_a, b, op);
362 }
Aart Bik471a2032015-09-04 18:22:11 -0700363 return CreateInduction(a->induction_class, new_a, new_b);
Aart Bik30efb4e2015-07-30 12:14:31 -0700364 }
365 }
366 return nullptr;
367}
368
369HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::TransferMul(InductionInfo* a,
370 InductionInfo* b) {
Aart Bike609b7c2015-08-27 13:46:58 -0700371 // Transfer over a multiplication: any invariant, linear, wrap-around, or periodic
372 // can be multiplied with an invariant to yield a similar but multiplied result.
373 // Two non-invariant inputs cannot be multiplied, however.
Aart Bik30efb4e2015-07-30 12:14:31 -0700374 if (a != nullptr && b != nullptr) {
375 if (a->induction_class == kInvariant && b->induction_class == kInvariant) {
Aart Bik471a2032015-09-04 18:22:11 -0700376 return CreateInvariantOp(kMul, a, b);
Aart Bike609b7c2015-08-27 13:46:58 -0700377 } else if (a->induction_class == kInvariant) {
Aart Bik471a2032015-09-04 18:22:11 -0700378 return CreateInduction(b->induction_class, TransferMul(a, b->op_a), TransferMul(a, b->op_b));
Aart Bike609b7c2015-08-27 13:46:58 -0700379 } else if (b->induction_class == kInvariant) {
Aart Bik471a2032015-09-04 18:22:11 -0700380 return CreateInduction(a->induction_class, TransferMul(a->op_a, b), TransferMul(a->op_b, b));
Aart Bike609b7c2015-08-27 13:46:58 -0700381 }
382 }
383 return nullptr;
384}
385
386HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::TransferShl(InductionInfo* a,
387 InductionInfo* b,
Aart Bikd14c5952015-09-08 15:25:15 -0700388 Primitive::Type type) {
Aart Bike609b7c2015-08-27 13:46:58 -0700389 // Transfer over a shift left: treat shift by restricted constant as equivalent multiplication.
Aart Bik471a2032015-09-04 18:22:11 -0700390 int64_t value = -1;
391 if (a != nullptr && IsIntAndGet(b, &value)) {
Aart Bike609b7c2015-08-27 13:46:58 -0700392 // Obtain the constant needed for the multiplication. This yields an existing instruction
393 // if the constants is already there. Otherwise, this has a side effect on the HIR.
394 // The restriction on the shift factor avoids generating a negative constant
395 // (viz. 1 << 31 and 1L << 63 set the sign bit). The code assumes that generalization
396 // for shift factors outside [0,32) and [0,64) ranges is done by earlier simplification.
Aart Bikd14c5952015-09-08 15:25:15 -0700397 if ((type == Primitive::kPrimInt && 0 <= value && value < 31) ||
398 (type == Primitive::kPrimLong && 0 <= value && value < 63)) {
399 return TransferMul(a, CreateConstant(1 << value, type));
Aart Bik30efb4e2015-07-30 12:14:31 -0700400 }
401 }
402 return nullptr;
403}
404
405HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::TransferNeg(InductionInfo* a) {
Aart Bike609b7c2015-08-27 13:46:58 -0700406 // Transfer over a unary negation: an invariant, linear, wrap-around, or periodic input
407 // yields a similar but negated induction as result.
Aart Bik30efb4e2015-07-30 12:14:31 -0700408 if (a != nullptr) {
409 if (a->induction_class == kInvariant) {
Aart Bik471a2032015-09-04 18:22:11 -0700410 return CreateInvariantOp(kNeg, nullptr, a);
Aart Bik30efb4e2015-07-30 12:14:31 -0700411 }
Aart Bik471a2032015-09-04 18:22:11 -0700412 return CreateInduction(a->induction_class, TransferNeg(a->op_a), TransferNeg(a->op_b));
Aart Bik30efb4e2015-07-30 12:14:31 -0700413 }
414 return nullptr;
415}
416
Aart Bikf475bee2015-09-16 12:50:25 -0700417HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::SolvePhi(HInstruction* phi,
418 size_t input_index) {
419 // Match all phi inputs from input_index onwards exactly.
420 const size_t count = phi->InputCount();
421 DCHECK_LT(input_index, count);
422 auto ita = cycle_.find(phi->InputAt(input_index));
Aart Bik30efb4e2015-07-30 12:14:31 -0700423 if (ita != cycle_.end()) {
Aart Bikf475bee2015-09-16 12:50:25 -0700424 for (size_t i = input_index + 1; i < count; i++) {
425 auto itb = cycle_.find(phi->InputAt(i));
426 if (itb == cycle_.end() ||
427 !HInductionVarAnalysis::InductionEqual(ita->second, itb->second)) {
Aart Bik30efb4e2015-07-30 12:14:31 -0700428 return nullptr;
429 }
430 }
Aart Bikf475bee2015-09-16 12:50:25 -0700431 return ita->second;
432 }
433 return nullptr;
434}
435
436HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::SolvePhiAllInputs(
437 HLoopInformation* loop,
438 HInstruction* entry_phi,
439 HInstruction* phi) {
440 // Match all phi inputs.
441 InductionInfo* match = SolvePhi(phi, /* input_index */ 0);
442 if (match != nullptr) {
443 return match;
Aart Bik30efb4e2015-07-30 12:14:31 -0700444 }
Aart Bik30efb4e2015-07-30 12:14:31 -0700445
Aart Bikf475bee2015-09-16 12:50:25 -0700446 // Otherwise, try to solve for a periodic seeded from phi onward.
447 // Only tight multi-statement cycles are considered in order to
448 // simplify rotating the periodic during the final classification.
449 if (phi->IsLoopHeaderPhi() && phi->InputCount() == 2) {
450 InductionInfo* a = LookupInfo(loop, phi->InputAt(0));
Aart Bike609b7c2015-08-27 13:46:58 -0700451 if (a != nullptr && a->induction_class == kInvariant) {
Aart Bikf475bee2015-09-16 12:50:25 -0700452 if (phi->InputAt(1) == entry_phi) {
453 InductionInfo* initial = LookupInfo(loop, entry_phi->InputAt(0));
Aart Bik471a2032015-09-04 18:22:11 -0700454 return CreateInduction(kPeriodic, a, initial);
Aart Bike609b7c2015-08-27 13:46:58 -0700455 }
Aart Bikf475bee2015-09-16 12:50:25 -0700456 InductionInfo* b = SolvePhi(phi, /* input_index */ 1);
457 if (b != nullptr && b->induction_class == kPeriodic) {
458 return CreateInduction(kPeriodic, a, b);
Aart Bik30efb4e2015-07-30 12:14:31 -0700459 }
460 }
461 }
Aart Bik30efb4e2015-07-30 12:14:31 -0700462 return nullptr;
463}
464
Aart Bike609b7c2015-08-27 13:46:58 -0700465HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::SolveAddSub(HLoopInformation* loop,
Aart Bikf475bee2015-09-16 12:50:25 -0700466 HInstruction* entry_phi,
Aart Bike609b7c2015-08-27 13:46:58 -0700467 HInstruction* instruction,
468 HInstruction* x,
469 HInstruction* y,
470 InductionOp op,
471 bool is_first_call) {
472 // Solve within a cycle over an addition or subtraction: adding or subtracting an
473 // invariant value, seeded from phi, keeps adding to the stride of the induction.
474 InductionInfo* b = LookupInfo(loop, y);
475 if (b != nullptr && b->induction_class == kInvariant) {
Aart Bikf475bee2015-09-16 12:50:25 -0700476 if (x == entry_phi) {
Aart Bik471a2032015-09-04 18:22:11 -0700477 return (op == kAdd) ? b : CreateInvariantOp(kNeg, nullptr, b);
Aart Bike609b7c2015-08-27 13:46:58 -0700478 }
479 auto it = cycle_.find(x);
480 if (it != cycle_.end()) {
481 InductionInfo* a = it->second;
482 if (a->induction_class == kInvariant) {
Aart Bik471a2032015-09-04 18:22:11 -0700483 return CreateInvariantOp(op, a, b);
Aart Bike609b7c2015-08-27 13:46:58 -0700484 }
Aart Bik30efb4e2015-07-30 12:14:31 -0700485 }
486 }
Aart Bike609b7c2015-08-27 13:46:58 -0700487
488 // Try some alternatives before failing.
489 if (op == kAdd) {
490 // Try the other way around for an addition if considered for first time.
491 if (is_first_call) {
Aart Bikf475bee2015-09-16 12:50:25 -0700492 return SolveAddSub(loop, entry_phi, instruction, y, x, op, false);
Aart Bike609b7c2015-08-27 13:46:58 -0700493 }
494 } else if (op == kSub) {
Aart Bikf475bee2015-09-16 12:50:25 -0700495 // Solve within a tight cycle that is formed by exactly two instructions,
496 // one phi and one update, for a periodic idiom of the form k = c - k;
497 if (y == entry_phi && entry_phi->InputCount() == 2 && instruction == entry_phi->InputAt(1)) {
Aart Bike609b7c2015-08-27 13:46:58 -0700498 InductionInfo* a = LookupInfo(loop, x);
499 if (a != nullptr && a->induction_class == kInvariant) {
Aart Bikf475bee2015-09-16 12:50:25 -0700500 InductionInfo* initial = LookupInfo(loop, entry_phi->InputAt(0));
Aart Bik471a2032015-09-04 18:22:11 -0700501 return CreateInduction(kPeriodic, CreateInvariantOp(kSub, a, initial), initial);
Aart Bike609b7c2015-08-27 13:46:58 -0700502 }
503 }
504 }
505
Aart Bik30efb4e2015-07-30 12:14:31 -0700506 return nullptr;
507}
508
Aart Bikd14c5952015-09-08 15:25:15 -0700509void HInductionVarAnalysis::VisitControl(HLoopInformation* loop) {
510 HInstruction* control = loop->GetHeader()->GetLastInstruction();
511 if (control->IsIf()) {
512 HIf* ifs = control->AsIf();
513 HBasicBlock* if_true = ifs->IfTrueSuccessor();
514 HBasicBlock* if_false = ifs->IfFalseSuccessor();
515 HInstruction* if_expr = ifs->InputAt(0);
516 // Determine if loop has following structure in header.
517 // loop-header: ....
518 // if (condition) goto X
519 if (if_expr->IsCondition()) {
520 HCondition* condition = if_expr->AsCondition();
521 InductionInfo* a = LookupInfo(loop, condition->InputAt(0));
522 InductionInfo* b = LookupInfo(loop, condition->InputAt(1));
523 Primitive::Type type = condition->InputAt(0)->GetType();
524 // Determine if the loop control uses integral arithmetic and an if-exit (X outside) or an
525 // if-iterate (X inside), always expressed as if-iterate when passing into VisitCondition().
526 if (type != Primitive::kPrimInt && type != Primitive::kPrimLong) {
527 // Loop control is not 32/64-bit integral.
528 } else if (a == nullptr || b == nullptr) {
529 // Loop control is not a sequence.
530 } else if (if_true->GetLoopInformation() != loop && if_false->GetLoopInformation() == loop) {
531 VisitCondition(loop, a, b, type, condition->GetOppositeCondition());
532 } else if (if_true->GetLoopInformation() == loop && if_false->GetLoopInformation() != loop) {
533 VisitCondition(loop, a, b, type, condition->GetCondition());
534 }
535 }
536 }
537}
538
539void HInductionVarAnalysis::VisitCondition(HLoopInformation* loop,
540 InductionInfo* a,
541 InductionInfo* b,
542 Primitive::Type type,
543 IfCondition cmp) {
544 if (a->induction_class == kInvariant && b->induction_class == kLinear) {
Aart Bikf475bee2015-09-16 12:50:25 -0700545 // Swap condition if induction is at right-hand-side (e.g. U > i is same as i < U).
Aart Bikd14c5952015-09-08 15:25:15 -0700546 switch (cmp) {
547 case kCondLT: VisitCondition(loop, b, a, type, kCondGT); break;
548 case kCondLE: VisitCondition(loop, b, a, type, kCondGE); break;
549 case kCondGT: VisitCondition(loop, b, a, type, kCondLT); break;
550 case kCondGE: VisitCondition(loop, b, a, type, kCondLE); break;
Aart Bikf475bee2015-09-16 12:50:25 -0700551 case kCondNE: VisitCondition(loop, b, a, type, kCondNE); break;
Aart Bikd14c5952015-09-08 15:25:15 -0700552 default: break;
553 }
554 } else if (a->induction_class == kLinear && b->induction_class == kInvariant) {
Aart Bikf475bee2015-09-16 12:50:25 -0700555 // Analyze condition with induction at left-hand-side (e.g. i < U).
Aart Bikd14c5952015-09-08 15:25:15 -0700556 InductionInfo* stride = a->op_a;
557 InductionInfo* lo_val = a->op_b;
558 InductionInfo* hi_val = b;
Aart Bikf475bee2015-09-16 12:50:25 -0700559 // Analyze stride (may be compound).
Aart Bik22af3be2015-09-10 12:50:58 -0700560 InductionVarRange::Value v1 = InductionVarRange::GetMin(stride, nullptr);
561 InductionVarRange::Value v2 = InductionVarRange::GetMax(stride, nullptr);
Aart Bikf475bee2015-09-16 12:50:25 -0700562 if (v1.a_constant != 0 || v2.a_constant != 0 || v1.b_constant != v2.b_constant) {
563 return;
564 }
565 // Rewrite safe condition i != U with unit stride into i < U or i > U
566 // (unit stride guarantees that the end condition is always reached).
567 const int32_t stride_value = v1.b_constant;
568 int64_t lo_value = 0;
569 int64_t hi_value = 0;
570 if (cmp == kCondNE && IsIntAndGet(lo_val, &lo_value) && IsIntAndGet(hi_val, &hi_value)) {
571 if ((stride_value == +1 && lo_value < hi_value) ||
572 (stride_value == -1 && lo_value > hi_value)) {
573 cmp = stride_value > 0 ? kCondLT : kCondGT;
Aart Bikd14c5952015-09-08 15:25:15 -0700574 }
575 }
Aart Bikf475bee2015-09-16 12:50:25 -0700576 // Normalize a linear loop control with a nonzero stride:
577 // stride > 0, either i < U or i <= U
578 // stride < 0, either i > U or i >= U
579 //
580 // TODO: construct conditions for constant/symbolic safety of trip-count
581 //
582 if ((stride_value > 0 && (cmp == kCondLT || cmp == kCondLE)) ||
583 (stride_value < 0 && (cmp == kCondGT || cmp == kCondGE))) {
584 VisitTripCount(loop, lo_val, hi_val, stride, stride_value, type, cmp);
585 }
Aart Bikd14c5952015-09-08 15:25:15 -0700586 }
587}
588
589void HInductionVarAnalysis::VisitTripCount(HLoopInformation* loop,
590 InductionInfo* lo_val,
591 InductionInfo* hi_val,
592 InductionInfo* stride,
593 int32_t stride_value,
594 Primitive::Type type,
Aart Bikf475bee2015-09-16 12:50:25 -0700595 IfCondition cmp) {
Aart Bikd14c5952015-09-08 15:25:15 -0700596 // Any loop of the general form:
597 //
598 // for (i = L; i <= U; i += S) // S > 0
599 // or for (i = L; i >= U; i += S) // S < 0
600 // .. i ..
601 //
602 // can be normalized into:
603 //
604 // for (n = 0; n < TC; n++) // where TC = (U + S - L) / S
605 // .. L + S * n ..
606 //
Aart Bikf475bee2015-09-16 12:50:25 -0700607 // NOTE: The TC (trip-count) expression is only valid when safe. Otherwise TC is 0
608 // (or possibly infinite). Also, the expression assumes the loop does not have
609 // early-exits. Otherwise, TC is an upper bound.
Aart Bikd14c5952015-09-08 15:25:15 -0700610 //
Aart Bikf475bee2015-09-16 12:50:25 -0700611 bool cancels = (cmp == kCondLT || cmp == kCondGT) && std::abs(stride_value) == 1;
Aart Bikd14c5952015-09-08 15:25:15 -0700612 if (!cancels) {
613 // Convert exclusive integral inequality into inclusive integral inequality,
614 // viz. condition i < U is i <= U - 1 and condition i > U is i >= U + 1.
Aart Bikf475bee2015-09-16 12:50:25 -0700615 if (cmp == kCondLT) {
616 hi_val = CreateInvariantOp(kSub, hi_val, CreateConstant(1, type));
617 } else if (cmp == kCondGT) {
618 hi_val = CreateInvariantOp(kAdd, hi_val, CreateConstant(1, type));
Aart Bikd14c5952015-09-08 15:25:15 -0700619 }
620 // Compensate for stride.
621 hi_val = CreateInvariantOp(kAdd, hi_val, stride);
622 }
623
624 // Assign the trip-count expression to the loop control. Clients that use the information
Aart Bikf475bee2015-09-16 12:50:25 -0700625 // should be aware that the expression is only valid in the loop-body proper (when symbolically
626 // safe), and not yet in the loop-header (unless constant safe). If the loop has any early exits,
627 // the trip-count forms a conservative upper bound on the number of loop iterations.
Aart Bikd14c5952015-09-08 15:25:15 -0700628 InductionInfo* trip_count =
629 CreateInvariantOp(kDiv, CreateInvariantOp(kSub, hi_val, lo_val), stride);
630 AssignInfo(loop, loop->GetHeader()->GetLastInstruction(), trip_count);
631}
632
Aart Bik30efb4e2015-07-30 12:14:31 -0700633void HInductionVarAnalysis::AssignInfo(HLoopInformation* loop,
634 HInstruction* instruction,
635 InductionInfo* info) {
Aart Bike609b7c2015-08-27 13:46:58 -0700636 auto it = induction_.find(loop);
637 if (it == induction_.end()) {
638 it = induction_.Put(loop,
639 ArenaSafeMap<HInstruction*, InductionInfo*>(
640 std::less<HInstruction*>(), graph_->GetArena()->Adapter()));
641 }
642 it->second.Put(instruction, info);
Aart Bik30efb4e2015-07-30 12:14:31 -0700643}
644
Aart Bike609b7c2015-08-27 13:46:58 -0700645HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::LookupInfo(HLoopInformation* loop,
646 HInstruction* instruction) {
647 auto it = induction_.find(loop);
648 if (it != induction_.end()) {
649 auto loop_it = it->second.find(instruction);
650 if (loop_it != it->second.end()) {
651 return loop_it->second;
652 }
Aart Bik30efb4e2015-07-30 12:14:31 -0700653 }
Aart Bike609b7c2015-08-27 13:46:58 -0700654 if (IsLoopInvariant(loop, instruction)) {
Aart Bik471a2032015-09-04 18:22:11 -0700655 InductionInfo* info = CreateInvariantFetch(instruction);
Aart Bike609b7c2015-08-27 13:46:58 -0700656 AssignInfo(loop, instruction, info);
657 return info;
658 }
659 return nullptr;
Aart Bik30efb4e2015-07-30 12:14:31 -0700660}
661
Aart Bikd14c5952015-09-08 15:25:15 -0700662HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::CreateConstant(int64_t value,
663 Primitive::Type type) {
664 if (type == Primitive::kPrimInt) {
665 return CreateInvariantFetch(graph_->GetIntConstant(value));
666 }
667 DCHECK_EQ(type, Primitive::kPrimLong);
668 return CreateInvariantFetch(graph_->GetLongConstant(value));
669}
670
Aart Bik471a2032015-09-04 18:22:11 -0700671HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::CreateSimplifiedInvariant(
672 InductionOp op,
673 InductionInfo* a,
674 InductionInfo* b) {
675 // Perform some light-weight simplifications during construction of a new invariant.
676 // This often safes memory and yields a more concise representation of the induction.
677 // More exhaustive simplifications are done by later phases once induction nodes are
678 // translated back into HIR code (e.g. by loop optimizations or BCE).
679 int64_t value = -1;
680 if (IsIntAndGet(a, &value)) {
681 if (value == 0) {
682 // Simplify 0 + b = b, 0 * b = 0.
683 if (op == kAdd) {
684 return b;
685 } else if (op == kMul) {
686 return a;
687 }
Aart Bikd14c5952015-09-08 15:25:15 -0700688 } else if (op == kMul) {
689 // Simplify 1 * b = b, -1 * b = -b
690 if (value == 1) {
691 return b;
692 } else if (value == -1) {
693 op = kNeg;
694 a = nullptr;
695 }
Aart Bik471a2032015-09-04 18:22:11 -0700696 }
697 }
698 if (IsIntAndGet(b, &value)) {
699 if (value == 0) {
Aart Bikd14c5952015-09-08 15:25:15 -0700700 // Simplify a + 0 = a, a - 0 = a, a * 0 = 0, -0 = 0.
Aart Bik471a2032015-09-04 18:22:11 -0700701 if (op == kAdd || op == kSub) {
702 return a;
703 } else if (op == kMul || op == kNeg) {
704 return b;
705 }
Aart Bikd14c5952015-09-08 15:25:15 -0700706 } else if (op == kMul || op == kDiv) {
707 // Simplify a * 1 = a, a / 1 = a, a * -1 = -a, a / -1 = -a
708 if (value == 1) {
709 return a;
710 } else if (value == -1) {
711 op = kNeg;
712 b = a;
713 a = nullptr;
714 }
Aart Bik471a2032015-09-04 18:22:11 -0700715 }
716 } else if (b->operation == kNeg) {
Aart Bikd14c5952015-09-08 15:25:15 -0700717 // Simplify a + (-b) = a - b, a - (-b) = a + b, -(-b) = b.
718 if (op == kAdd) {
719 op = kSub;
720 b = b->op_b;
721 } else if (op == kSub) {
722 op = kAdd;
723 b = b->op_b;
724 } else if (op == kNeg) {
725 return b->op_b;
Aart Bik471a2032015-09-04 18:22:11 -0700726 }
727 }
728 return new (graph_->GetArena()) InductionInfo(kInvariant, op, a, b, nullptr);
729}
730
Aart Bik30efb4e2015-07-30 12:14:31 -0700731bool HInductionVarAnalysis::InductionEqual(InductionInfo* info1,
732 InductionInfo* info2) {
733 // Test structural equality only, without accounting for simplifications.
734 if (info1 != nullptr && info2 != nullptr) {
735 return
736 info1->induction_class == info2->induction_class &&
737 info1->operation == info2->operation &&
738 info1->fetch == info2->fetch &&
739 InductionEqual(info1->op_a, info2->op_a) &&
740 InductionEqual(info1->op_b, info2->op_b);
741 }
742 // Otherwise only two nullptrs are considered equal.
743 return info1 == info2;
744}
745
Aart Bik471a2032015-09-04 18:22:11 -0700746bool HInductionVarAnalysis::IsIntAndGet(InductionInfo* info, int64_t* value) {
747 if (info != nullptr && info->induction_class == kInvariant && info->operation == kFetch) {
748 DCHECK(info->fetch);
749 if (info->fetch->IsIntConstant()) {
750 *value = info->fetch->AsIntConstant()->GetValue();
751 return true;
752 } else if (info->fetch->IsLongConstant()) {
753 *value = info->fetch->AsLongConstant()->GetValue();
754 return true;
755 }
756 }
757 return false;
758}
759
Aart Bik30efb4e2015-07-30 12:14:31 -0700760std::string HInductionVarAnalysis::InductionToString(InductionInfo* info) {
761 if (info != nullptr) {
762 if (info->induction_class == kInvariant) {
Aart Bik471a2032015-09-04 18:22:11 -0700763 int64_t value = -1;
Aart Bik30efb4e2015-07-30 12:14:31 -0700764 std::string inv = "(";
765 inv += InductionToString(info->op_a);
766 switch (info->operation) {
Aart Bike609b7c2015-08-27 13:46:58 -0700767 case kNop: inv += " @ "; break;
768 case kAdd: inv += " + "; break;
Aart Bik30efb4e2015-07-30 12:14:31 -0700769 case kSub:
Aart Bike609b7c2015-08-27 13:46:58 -0700770 case kNeg: inv += " - "; break;
771 case kMul: inv += " * "; break;
772 case kDiv: inv += " / "; break;
Aart Bik30efb4e2015-07-30 12:14:31 -0700773 case kFetch:
Aart Bike609b7c2015-08-27 13:46:58 -0700774 DCHECK(info->fetch);
Aart Bik471a2032015-09-04 18:22:11 -0700775 if (IsIntAndGet(info, &value)) {
776 inv += std::to_string(value);
777 } else {
778 inv += std::to_string(info->fetch->GetId()) + ":" + info->fetch->DebugName();
779 }
Aart Bik30efb4e2015-07-30 12:14:31 -0700780 break;
781 }
782 inv += InductionToString(info->op_b);
783 return inv + ")";
784 } else {
Aart Bike609b7c2015-08-27 13:46:58 -0700785 DCHECK(info->operation == kNop);
Aart Bik30efb4e2015-07-30 12:14:31 -0700786 if (info->induction_class == kLinear) {
787 return "(" + InductionToString(info->op_a) + " * i + " +
788 InductionToString(info->op_b) + ")";
789 } else if (info->induction_class == kWrapAround) {
790 return "wrap(" + InductionToString(info->op_a) + ", " +
791 InductionToString(info->op_b) + ")";
792 } else if (info->induction_class == kPeriodic) {
793 return "periodic(" + InductionToString(info->op_a) + ", " +
794 InductionToString(info->op_b) + ")";
795 }
796 }
797 }
798 return "";
799}
800
801} // namespace art