blob: 3b5a2f1f9dedde2702ddaf41d8764b54bda107d1 [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"
Vladimir Markode4d1952022-03-07 09:29:40 +000018
Aart Bik22af3be2015-09-10 12:50:58 -070019#include "induction_var_range.h"
Aart Bik30efb4e2015-07-30 12:14:31 -070020
Vladimir Marko0a516052019-10-14 13:00:44 +000021namespace art {
Aart Bik30efb4e2015-07-30 12:14:31 -070022
23/**
Aart Bik0d345cf2016-03-16 10:49:38 -070024 * Returns true if the from/to types denote a narrowing, integral conversion (precision loss).
25 */
Vladimir Marko0ebe0d82017-09-21 22:50:39 +010026static bool IsNarrowingIntegralConversion(DataType::Type from, DataType::Type to) {
Aart Bik0d345cf2016-03-16 10:49:38 -070027 switch (from) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +010028 case DataType::Type::kInt64:
Vladimir Markod5d2f2c2017-09-26 12:37:26 +010029 return to == DataType::Type::kUint8 ||
30 to == DataType::Type::kInt8 ||
31 to == DataType::Type::kUint16 ||
32 to == DataType::Type::kInt16 ||
33 to == DataType::Type::kInt32;
Vladimir Marko0ebe0d82017-09-21 22:50:39 +010034 case DataType::Type::kInt32:
Vladimir Markod5d2f2c2017-09-26 12:37:26 +010035 return to == DataType::Type::kUint8 ||
36 to == DataType::Type::kInt8 ||
37 to == DataType::Type::kUint16 ||
38 to == DataType::Type::kInt16;
Vladimir Marko0ebe0d82017-09-21 22:50:39 +010039 case DataType::Type::kUint16:
40 case DataType::Type::kInt16:
Vladimir Markod5d2f2c2017-09-26 12:37:26 +010041 return to == DataType::Type::kUint8 || to == DataType::Type::kInt8;
Aart Bik0d345cf2016-03-16 10:49:38 -070042 default:
43 return false;
44 }
45}
46
47/**
Aart Bike6bd0272016-12-16 13:57:52 -080048 * Returns result of implicit widening type conversion done in HIR.
Aart Bik0d345cf2016-03-16 10:49:38 -070049 */
Vladimir Marko0ebe0d82017-09-21 22:50:39 +010050static DataType::Type ImplicitConversion(DataType::Type type) {
Aart Bike6bd0272016-12-16 13:57:52 -080051 switch (type) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +010052 case DataType::Type::kBool:
Vladimir Markod5d2f2c2017-09-26 12:37:26 +010053 case DataType::Type::kUint8:
54 case DataType::Type::kInt8:
55 case DataType::Type::kUint16:
56 case DataType::Type::kInt16:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +010057 return DataType::Type::kInt32;
Aart Bike6bd0272016-12-16 13:57:52 -080058 default:
59 return type;
60 }
Aart Bik0d345cf2016-03-16 10:49:38 -070061}
62
Aart Bikceb06932017-11-13 10:31:17 -080063/**
64 * Returns true if loop is guarded by "a cmp b" on entry.
65 */
Vladimir Marko8d100ba2022-03-04 10:13:10 +000066static bool IsGuardedBy(const HLoopInformation* loop,
Aart Bikceb06932017-11-13 10:31:17 -080067 IfCondition cmp,
68 HInstruction* a,
69 HInstruction* b) {
70 // Chase back through straightline code to the first potential
71 // block that has a control dependence.
72 // guard: if (x) bypass
73 // |
74 // entry: straightline code
75 // |
76 // preheader
77 // |
78 // header
79 HBasicBlock* guard = loop->GetPreHeader();
80 HBasicBlock* entry = loop->GetHeader();
81 while (guard->GetPredecessors().size() == 1 &&
82 guard->GetSuccessors().size() == 1) {
83 entry = guard;
84 guard = guard->GetSinglePredecessor();
85 }
86 // Find guard.
87 HInstruction* control = guard->GetLastInstruction();
88 if (!control->IsIf()) {
89 return false;
90 }
91 HIf* ifs = control->AsIf();
92 HInstruction* if_expr = ifs->InputAt(0);
93 if (if_expr->IsCondition()) {
94 IfCondition other_cmp = ifs->IfTrueSuccessor() == entry
95 ? if_expr->AsCondition()->GetCondition()
96 : if_expr->AsCondition()->GetOppositeCondition();
97 if (if_expr->InputAt(0) == a && if_expr->InputAt(1) == b) {
98 return cmp == other_cmp;
99 } else if (if_expr->InputAt(1) == a && if_expr->InputAt(0) == b) {
100 switch (cmp) {
101 case kCondLT: return other_cmp == kCondGT;
102 case kCondLE: return other_cmp == kCondGE;
103 case kCondGT: return other_cmp == kCondLT;
104 case kCondGE: return other_cmp == kCondLE;
105 default: LOG(FATAL) << "unexpected cmp: " << cmp;
106 }
107 }
108 }
109 return false;
110}
111
112/* Finds first loop header phi use. */
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000113HInstruction* FindFirstLoopHeaderPhiUse(const HLoopInformation* loop, HInstruction* instruction) {
Aart Bikceb06932017-11-13 10:31:17 -0800114 for (const HUseListNode<HInstruction*>& use : instruction->GetUses()) {
115 if (use.GetUser()->GetBlock() == loop->GetHeader() &&
116 use.GetUser()->IsPhi() &&
117 use.GetUser()->InputAt(1) == instruction) {
118 return use.GetUser();
119 }
120 }
121 return nullptr;
122}
123
124/**
125 * Relinks the Phi structure after break-loop rewriting.
126 */
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000127static bool FixOutsideUse(const HLoopInformation* loop,
Vladimir Markode4d1952022-03-07 09:29:40 +0000128 HInstruction* instruction,
129 HInstruction* replacement,
130 bool rewrite) {
Aart Bikceb06932017-11-13 10:31:17 -0800131 // Deal with regular uses.
132 const HUseList<HInstruction*>& uses = instruction->GetUses();
133 for (auto it = uses.begin(), end = uses.end(); it != end; ) {
134 HInstruction* user = it->GetUser();
135 size_t index = it->GetIndex();
136 ++it; // increment prior to potential removal
137 if (user->GetBlock()->GetLoopInformation() != loop) {
138 if (replacement == nullptr) {
139 return false;
140 } else if (rewrite) {
141 user->ReplaceInput(replacement, index);
142 }
143 }
144 }
145 // Deal with environment uses.
146 const HUseList<HEnvironment*>& env_uses = instruction->GetEnvUses();
147 for (auto it = env_uses.begin(), end = env_uses.end(); it != end;) {
148 HEnvironment* user = it->GetUser();
149 size_t index = it->GetIndex();
150 ++it; // increment prior to potential removal
151 if (user->GetHolder()->GetBlock()->GetLoopInformation() != loop) {
152 if (replacement == nullptr) {
153 return false;
154 } else if (rewrite) {
Vladimir Markode4d1952022-03-07 09:29:40 +0000155 user->ReplaceInput(replacement, index);
Aart Bikceb06932017-11-13 10:31:17 -0800156 }
157 }
158 }
159 return true;
160}
161
162/**
163 * Test and rewrite the loop body of a break-loop. Returns true on success.
164 */
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000165static bool RewriteBreakLoopBody(const HLoopInformation* loop,
Vladimir Markode4d1952022-03-07 09:29:40 +0000166 HBasicBlock* body,
167 HInstruction* cond,
168 HInstruction* index,
169 HInstruction* upper,
170 bool rewrite) {
Aart Bikceb06932017-11-13 10:31:17 -0800171 // Deal with Phis. Outside use prohibited, except for index (which gets exit value).
172 for (HInstructionIterator it(loop->GetHeader()->GetPhis()); !it.Done(); it.Advance()) {
173 HInstruction* exit_value = it.Current() == index ? upper : nullptr;
174 if (!FixOutsideUse(loop, it.Current(), exit_value, rewrite)) {
175 return false;
176 }
177 }
178 // Deal with other statements in header.
Vladimir Markode4d1952022-03-07 09:29:40 +0000179 for (HInstruction* m = cond->GetPrevious(); m && !m->IsSuspendCheck();) {
180 HInstruction* p = m->GetPrevious();
Aart Bikceb06932017-11-13 10:31:17 -0800181 if (rewrite) {
182 m->MoveBefore(body->GetFirstInstruction(), false);
183 }
184 if (!FixOutsideUse(loop, m, FindFirstLoopHeaderPhiUse(loop, m), rewrite)) {
185 return false;
186 }
Vladimir Markode4d1952022-03-07 09:29:40 +0000187 m = p;
Aart Bikceb06932017-11-13 10:31:17 -0800188 }
189 return true;
190}
191
Aart Bik30efb4e2015-07-30 12:14:31 -0700192//
Vladimir Markode4d1952022-03-07 09:29:40 +0000193// Class members.
Aart Bik30efb4e2015-07-30 12:14:31 -0700194//
195
Vladimir Markode4d1952022-03-07 09:29:40 +0000196struct HInductionVarAnalysis::NodeInfo {
197 explicit NodeInfo(uint32_t d) : depth(d), done(false) {}
198 uint32_t depth;
199 bool done;
200};
201
202struct HInductionVarAnalysis::StackEntry {
203 StackEntry(HInstruction* insn, NodeInfo* info, size_t link = std::numeric_limits<size_t>::max())
204 : instruction(insn),
205 node_info(info),
206 user_link(link),
207 num_visited_inputs(0u),
208 low_depth(info->depth) {}
209
210 HInstruction* instruction;
211 NodeInfo* node_info;
212 size_t user_link; // Stack index of the user that is visiting this input.
213 size_t num_visited_inputs;
214 size_t low_depth;
215};
216
Aart Bik2ca10eb2017-11-15 15:17:53 -0800217HInductionVarAnalysis::HInductionVarAnalysis(HGraph* graph, const char* name)
218 : HOptimization(graph, name),
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000219 induction_(std::less<const HLoopInformation*>(),
Vladimir Markoca6fff82017-10-03 14:49:14 +0100220 graph->GetAllocator()->Adapter(kArenaAllocInductionVarAnalysis)),
Aart Bikcc42be02016-10-20 16:14:16 -0700221 cycles_(std::less<HPhi*>(),
Vladimir Markoca6fff82017-10-03 14:49:14 +0100222 graph->GetAllocator()->Adapter(kArenaAllocInductionVarAnalysis)) {
Aart Bik30efb4e2015-07-30 12:14:31 -0700223}
224
Aart Bik24773202018-04-26 10:28:51 -0700225bool HInductionVarAnalysis::Run() {
Aart Bik7d57d7f2015-12-09 14:39:48 -0800226 // Detects sequence variables (generalized induction variables) during an outer to inner
227 // traversal of all loops using Gerlek's algorithm. The order is important to enable
228 // range analysis on outer loop while visiting inner loops.
Vladimir Marko2c45bc92016-10-25 16:54:12 +0100229 for (HBasicBlock* graph_block : graph_->GetReversePostOrder()) {
Nicolas Geoffray15bd2282016-01-05 15:55:41 +0000230 // Don't analyze irreducible loops.
Nicolas Geoffray15bd2282016-01-05 15:55:41 +0000231 if (graph_block->IsLoopHeader() && !graph_block->GetLoopInformation()->IsIrreducible()) {
Aart Bik30efb4e2015-07-30 12:14:31 -0700232 VisitLoop(graph_block->GetLoopInformation());
233 }
234 }
Aart Bik24773202018-04-26 10:28:51 -0700235 return !induction_.empty();
Aart Bik30efb4e2015-07-30 12:14:31 -0700236}
237
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000238void HInductionVarAnalysis::VisitLoop(const HLoopInformation* loop) {
Vladimir Markode4d1952022-03-07 09:29:40 +0000239 ScopedArenaAllocator local_allocator(graph_->GetArenaStack());
240 ScopedArenaSafeMap<HInstruction*, NodeInfo> visited_instructions(
241 std::less<HInstruction*>(), local_allocator.Adapter(kArenaAllocInductionVarAnalysis));
242
Aart Bik30efb4e2015-07-30 12:14:31 -0700243 // Find strongly connected components (SSCs) in the SSA graph of this loop using Tarjan's
244 // algorithm. Due to the descendant-first nature, classification happens "on-demand".
Vladimir Markode4d1952022-03-07 09:29:40 +0000245 size_t global_depth = 0;
Aart Bik30efb4e2015-07-30 12:14:31 -0700246 for (HBlocksInLoopIterator it_loop(*loop); !it_loop.Done(); it_loop.Advance()) {
247 HBasicBlock* loop_block = it_loop.Current();
Aart Bike609b7c2015-08-27 13:46:58 -0700248 DCHECK(loop_block->IsInLoop());
Aart Bik30efb4e2015-07-30 12:14:31 -0700249 if (loop_block->GetLoopInformation() != loop) {
Aart Bik7dc96932016-10-12 10:01:05 -0700250 continue; // Inner loops visited later.
Aart Bik30efb4e2015-07-30 12:14:31 -0700251 }
252 // Visit phi-operations and instructions.
253 for (HInstructionIterator it(loop_block->GetPhis()); !it.Done(); it.Advance()) {
Vladimir Markode4d1952022-03-07 09:29:40 +0000254 global_depth = TryVisitNodes(loop, it.Current(), global_depth, &visited_instructions);
Aart Bik30efb4e2015-07-30 12:14:31 -0700255 }
256 for (HInstructionIterator it(loop_block->GetInstructions()); !it.Done(); it.Advance()) {
Vladimir Markode4d1952022-03-07 09:29:40 +0000257 global_depth = TryVisitNodes(loop, it.Current(), global_depth, &visited_instructions);
Aart Bik30efb4e2015-07-30 12:14:31 -0700258 }
259 }
260
Aart Bik78296912016-03-25 13:14:53 -0700261 // Determine the loop's trip-count.
Aart Bikd14c5952015-09-08 15:25:15 -0700262 VisitControl(loop);
Aart Bik30efb4e2015-07-30 12:14:31 -0700263}
264
Vladimir Markode4d1952022-03-07 09:29:40 +0000265size_t HInductionVarAnalysis::TryVisitNodes(
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000266 const HLoopInformation* loop,
Vladimir Markode4d1952022-03-07 09:29:40 +0000267 HInstruction* start_instruction,
268 size_t global_depth,
269 /*inout*/ ScopedArenaSafeMap<HInstruction*, NodeInfo>* visited_instructions) {
270 // This is recursion-free version of the SCC search algorithm. We have limited stack space,
271 // so recursion with the depth dependent on the input is undesirable as such depth is unlimited.
272 auto [it, inserted] =
273 visited_instructions->insert(std::make_pair(start_instruction, NodeInfo(global_depth + 1u)));
274 if (!inserted) {
275 return global_depth;
Aart Bik30efb4e2015-07-30 12:14:31 -0700276 }
Vladimir Markode4d1952022-03-07 09:29:40 +0000277 NodeInfo* start_info = &it->second;
278 ++global_depth;
279 DCHECK_EQ(global_depth, start_info->depth);
Aart Bik30efb4e2015-07-30 12:14:31 -0700280
Vladimir Markode4d1952022-03-07 09:29:40 +0000281 ScopedArenaVector<StackEntry> stack(visited_instructions->get_allocator());
282 stack.push_back({start_instruction, start_info});
Aart Bik30efb4e2015-07-30 12:14:31 -0700283
Vladimir Markode4d1952022-03-07 09:29:40 +0000284 size_t current_entry = 0u;
285 while (!stack.empty()) {
286 StackEntry& entry = stack[current_entry];
287
288 // Look for unvisited inputs (also known as "descentants").
289 bool visit_input = false;
290 auto inputs = entry.instruction->GetInputs();
291 while (entry.num_visited_inputs != inputs.size()) {
292 HInstruction* input = inputs[entry.num_visited_inputs];
293 ++entry.num_visited_inputs;
294 // If the definition is either outside the loop (loop invariant entry value)
295 // or assigned in inner loop (inner exit value), the input is not visited.
296 if (input->GetBlock()->GetLoopInformation() != loop) {
297 continue;
Aart Bik30efb4e2015-07-30 12:14:31 -0700298 }
Vladimir Markode4d1952022-03-07 09:29:40 +0000299 // Try visiting the input. If already visited, update `entry.low_depth`.
300 auto [input_it, input_inserted] =
301 visited_instructions->insert(std::make_pair(input, NodeInfo(global_depth + 1u)));
302 NodeInfo* input_info = &input_it->second;
303 if (input_inserted) {
304 // Push the input on the `stack` and visit it now.
305 ++global_depth;
306 DCHECK_EQ(global_depth, input_info->depth);
307 stack.push_back({input, input_info, current_entry});
308 current_entry = stack.size() - 1u;
309 visit_input = true;
310 break;
311 } else if (!input_info->done && input_info->depth < entry.low_depth) {
312 entry.low_depth = input_it->second.depth;
313 }
314 continue;
315 }
316 if (visit_input) {
317 continue; // Process the new top of the stack.
Aart Bik30efb4e2015-07-30 12:14:31 -0700318 }
319
Vladimir Markode4d1952022-03-07 09:29:40 +0000320 // All inputs of the current node have been visited.
321 // Check if we have found an input below this entry on the stack.
322 DCHECK(!entry.node_info->done);
323 size_t previous_entry = entry.user_link;
324 if (entry.node_info->depth > entry.low_depth) {
325 DCHECK_LT(previous_entry, current_entry) << entry.node_info->depth << " " << entry.low_depth;
326 entry.node_info->depth = entry.low_depth;
327 if (stack[previous_entry].low_depth > entry.low_depth) {
328 stack[previous_entry].low_depth = entry.low_depth;
329 }
Aart Bik30efb4e2015-07-30 12:14:31 -0700330 } else {
Vladimir Markode4d1952022-03-07 09:29:40 +0000331 // Classify the SCC we have just found.
332 ArrayRef<StackEntry> stack_tail = ArrayRef<StackEntry>(stack).SubArray(current_entry);
333 for (StackEntry& tail_entry : stack_tail) {
334 tail_entry.node_info->done = true;
335 }
336 if (current_entry + 1u == stack.size() && !entry.instruction->IsLoopHeaderPhi()) {
337 ClassifyTrivial(loop, entry.instruction);
338 } else {
339 ClassifyNonTrivial(loop, ArrayRef<const StackEntry>(stack_tail));
340 }
341 stack.erase(stack.begin() + current_entry, stack.end());
Aart Bik30efb4e2015-07-30 12:14:31 -0700342 }
Vladimir Markode4d1952022-03-07 09:29:40 +0000343 current_entry = previous_entry;
Aart Bik30efb4e2015-07-30 12:14:31 -0700344 }
Vladimir Markode4d1952022-03-07 09:29:40 +0000345
346 return global_depth;
Aart Bik30efb4e2015-07-30 12:14:31 -0700347}
348
Vladimir Markode4d1952022-03-07 09:29:40 +0000349/**
350 * Since graph traversal may enter a SCC at any position, an initial representation may be rotated,
351 * along dependences, viz. any of (a, b, c, d), (d, a, b, c) (c, d, a, b), (b, c, d, a) assuming
352 * a chain of dependences (mutual independent items may occur in arbitrary order). For proper
353 * classification, the lexicographically first loop-phi is rotated to the front. We do that
354 * as we extract the SCC instructions.
355 */
356void HInductionVarAnalysis::ExtractScc(ArrayRef<const StackEntry> stack_tail,
357 ScopedArenaVector<HInstruction*>* scc) {
358 // Find very first loop-phi.
359 HInstruction* phi = nullptr;
360 size_t split_pos = 0;
361 const size_t size = stack_tail.size();
362 for (size_t i = 0; i != size; ++i) {
363 const StackEntry& entry = stack_tail[i];
364 HInstruction* instruction = entry.instruction;
365 if (instruction->IsLoopHeaderPhi()) {
366 // All loop Phis in SCC come from the same loop header.
367 HBasicBlock* block = instruction->GetBlock();
368 DCHECK(block->GetLoopInformation()->GetHeader() == block);
369 DCHECK(phi == nullptr || phi->GetBlock() == block);
370 if (phi == nullptr || block->GetPhis().FoundBefore(instruction, phi)) {
371 phi = instruction;
372 split_pos = i + 1u;
373 }
374 }
Aart Bik30efb4e2015-07-30 12:14:31 -0700375 }
376
Vladimir Markode4d1952022-03-07 09:29:40 +0000377 // Extract SCC in two chunks.
378 DCHECK(scc->empty());
379 scc->reserve(size);
380 for (const StackEntry& entry : ReverseRange(stack_tail.SubArray(/*pos=*/ 0u, split_pos))) {
381 scc->push_back(entry.instruction);
Aart Bik30efb4e2015-07-30 12:14:31 -0700382 }
Vladimir Markode4d1952022-03-07 09:29:40 +0000383 for (const StackEntry& entry : ReverseRange(stack_tail.SubArray(/*pos=*/ split_pos))) {
384 scc->push_back(entry.instruction);
385 }
386 DCHECK_EQ(scc->size(), stack_tail.size());
Aart Bik30efb4e2015-07-30 12:14:31 -0700387}
388
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000389void HInductionVarAnalysis::ClassifyTrivial(const HLoopInformation* loop,
390 HInstruction* instruction) {
391 const HBasicBlock* context = instruction->GetBlock();
Vladimir Markode4d1952022-03-07 09:29:40 +0000392 DataType::Type type = instruction->GetType();
Aart Bik30efb4e2015-07-30 12:14:31 -0700393 InductionInfo* info = nullptr;
394 if (instruction->IsPhi()) {
Aart Bikd0a022d2016-12-13 11:22:31 -0800395 info = TransferPhi(loop, instruction, /*input_index*/ 0, /*adjust_input_size*/ 0);
Aart Bik30efb4e2015-07-30 12:14:31 -0700396 } else if (instruction->IsAdd()) {
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000397 info = TransferAddSub(context,
398 loop,
399 LookupInfo(loop, instruction->InputAt(0)),
Vladimir Markode4d1952022-03-07 09:29:40 +0000400 LookupInfo(loop, instruction->InputAt(1)),
401 kAdd,
402 type);
Aart Bik30efb4e2015-07-30 12:14:31 -0700403 } else if (instruction->IsSub()) {
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000404 info = TransferAddSub(context,
405 loop,
406 LookupInfo(loop, instruction->InputAt(0)),
Vladimir Markode4d1952022-03-07 09:29:40 +0000407 LookupInfo(loop, instruction->InputAt(1)),
408 kSub,
409 type);
Aart Bikc071a012016-12-01 10:22:31 -0800410 } else if (instruction->IsNeg()) {
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000411 info = TransferNeg(context, loop, LookupInfo(loop, instruction->InputAt(0)), type);
Aart Bik30efb4e2015-07-30 12:14:31 -0700412 } else if (instruction->IsMul()) {
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000413 info = TransferMul(context,
414 loop,
415 LookupInfo(loop, instruction->InputAt(0)),
Vladimir Markode4d1952022-03-07 09:29:40 +0000416 LookupInfo(loop, instruction->InputAt(1)),
417 type);
Aart Bike609b7c2015-08-27 13:46:58 -0700418 } else if (instruction->IsShl()) {
Aart Bikd0a022d2016-12-13 11:22:31 -0800419 HInstruction* mulc = GetShiftConstant(loop, instruction, /*initial*/ nullptr);
Aart Bikc071a012016-12-01 10:22:31 -0800420 if (mulc != nullptr) {
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000421 info = TransferMul(context,
422 loop,
423 LookupInfo(loop, instruction->InputAt(0)),
Vladimir Markode4d1952022-03-07 09:29:40 +0000424 LookupInfo(loop, mulc),
425 type);
Aart Bikc071a012016-12-01 10:22:31 -0800426 }
Aart Bikd0a022d2016-12-13 11:22:31 -0800427 } else if (instruction->IsSelect()) {
428 info = TransferPhi(loop, instruction, /*input_index*/ 0, /*adjust_input_size*/ 1);
Aart Bik0d345cf2016-03-16 10:49:38 -0700429 } else if (instruction->IsTypeConversion()) {
Aart Bike6bd0272016-12-16 13:57:52 -0800430 info = TransferConversion(LookupInfo(loop, instruction->InputAt(0)),
431 instruction->AsTypeConversion()->GetInputType(),
432 instruction->AsTypeConversion()->GetResultType());
Aart Bike609b7c2015-08-27 13:46:58 -0700433 } else if (instruction->IsBoundsCheck()) {
434 info = LookupInfo(loop, instruction->InputAt(0)); // Pass-through.
Aart Bik30efb4e2015-07-30 12:14:31 -0700435 }
436
437 // Successfully classified?
438 if (info != nullptr) {
439 AssignInfo(loop, instruction, info);
440 }
441}
442
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000443void HInductionVarAnalysis::ClassifyNonTrivial(const HLoopInformation* loop,
Vladimir Markode4d1952022-03-07 09:29:40 +0000444 ArrayRef<const StackEntry> stack_tail) {
445 const size_t size = stack_tail.size();
Aart Bike609b7c2015-08-27 13:46:58 -0700446 DCHECK_GE(size, 1u);
Vladimir Markode4d1952022-03-07 09:29:40 +0000447 DataType::Type type = stack_tail.back().instruction->GetType();
Aart Bik22af3be2015-09-10 12:50:58 -0700448
Vladimir Markode4d1952022-03-07 09:29:40 +0000449 ScopedArenaAllocator local_allocator(graph_->GetArenaStack());
450 ScopedArenaVector<HInstruction*> scc(local_allocator.Adapter(kArenaAllocInductionVarAnalysis));
451 ExtractScc(ArrayRef<const StackEntry>(stack_tail), &scc);
Aart Bik22af3be2015-09-10 12:50:58 -0700452
Aart Bikcc42be02016-10-20 16:14:16 -0700453 // Analyze from loop-phi onwards.
Vladimir Markode4d1952022-03-07 09:29:40 +0000454 HInstruction* phi = scc[0];
Aart Bikf475bee2015-09-16 12:50:25 -0700455 if (!phi->IsLoopHeaderPhi()) {
Aart Bik30efb4e2015-07-30 12:14:31 -0700456 return;
457 }
Aart Bikf475bee2015-09-16 12:50:25 -0700458
459 // External link should be loop invariant.
460 InductionInfo* initial = LookupInfo(loop, phi->InputAt(0));
Aart Bik30efb4e2015-07-30 12:14:31 -0700461 if (initial == nullptr || initial->induction_class != kInvariant) {
462 return;
463 }
464
Aart Bike6bd0272016-12-16 13:57:52 -0800465 // Store interesting cycle in each loop phi.
466 for (size_t i = 0; i < size; i++) {
Vladimir Markode4d1952022-03-07 09:29:40 +0000467 if (scc[i]->IsLoopHeaderPhi()) {
468 AssignCycle(scc[i]->AsPhi(), ArrayRef<HInstruction* const>(scc));
Aart Bike6bd0272016-12-16 13:57:52 -0800469 }
470 }
Aart Bikcc42be02016-10-20 16:14:16 -0700471
Aart Bikf475bee2015-09-16 12:50:25 -0700472 // Singleton is wrap-around induction if all internal links have the same meaning.
Aart Bik30efb4e2015-07-30 12:14:31 -0700473 if (size == 1) {
Aart Bikd0a022d2016-12-13 11:22:31 -0800474 InductionInfo* update = TransferPhi(loop, phi, /*input_index*/ 1, /*adjust_input_size*/ 0);
Aart Bik30efb4e2015-07-30 12:14:31 -0700475 if (update != nullptr) {
Aart Bikc071a012016-12-01 10:22:31 -0800476 AssignInfo(loop, phi, CreateInduction(kWrapAround,
477 kNop,
478 initial,
479 update,
480 /*fetch*/ nullptr,
Vladimir Markode4d1952022-03-07 09:29:40 +0000481 type));
Aart Bik30efb4e2015-07-30 12:14:31 -0700482 }
483 return;
484 }
485
Vladimir Markode4d1952022-03-07 09:29:40 +0000486 // Inspect remainder of the cycle that resides in `scc`. The `cycle` mapping assigns
Aart Bike609b7c2015-08-27 13:46:58 -0700487 // temporary meaning to its nodes, seeded from the phi instruction and back.
Vladimir Markode4d1952022-03-07 09:29:40 +0000488 ScopedArenaSafeMap<HInstruction*, InductionInfo*> cycle(
489 std::less<HInstruction*>(), local_allocator.Adapter(kArenaAllocInductionVarAnalysis));
Aart Bik22af3be2015-09-10 12:50:58 -0700490 for (size_t i = 1; i < size; i++) {
Vladimir Markode4d1952022-03-07 09:29:40 +0000491 HInstruction* instruction = scc[i];
Aart Bik30efb4e2015-07-30 12:14:31 -0700492 InductionInfo* update = nullptr;
Aart Bike609b7c2015-08-27 13:46:58 -0700493 if (instruction->IsPhi()) {
Vladimir Markode4d1952022-03-07 09:29:40 +0000494 update = SolvePhiAllInputs(loop, phi, instruction, cycle, type);
Aart Bike609b7c2015-08-27 13:46:58 -0700495 } else if (instruction->IsAdd()) {
Vladimir Markode4d1952022-03-07 09:29:40 +0000496 update = SolveAddSub(loop,
497 phi,
498 instruction,
499 instruction->InputAt(0),
500 instruction->InputAt(1),
501 kAdd,
502 cycle,
503 type);
Aart Bike609b7c2015-08-27 13:46:58 -0700504 } else if (instruction->IsSub()) {
Vladimir Markode4d1952022-03-07 09:29:40 +0000505 update = SolveAddSub(loop,
506 phi,
507 instruction,
508 instruction->InputAt(0),
509 instruction->InputAt(1),
510 kSub,
511 cycle,
512 type);
Aart Bikc071a012016-12-01 10:22:31 -0800513 } else if (instruction->IsMul()) {
Aart Bikdf7822e2016-12-06 10:05:30 -0800514 update = SolveOp(
Vladimir Markode4d1952022-03-07 09:29:40 +0000515 loop, phi, instruction, instruction->InputAt(0), instruction->InputAt(1), kMul, type);
Aart Bikc071a012016-12-01 10:22:31 -0800516 } else if (instruction->IsDiv()) {
Aart Bikdf7822e2016-12-06 10:05:30 -0800517 update = SolveOp(
Vladimir Markode4d1952022-03-07 09:29:40 +0000518 loop, phi, instruction, instruction->InputAt(0), instruction->InputAt(1), kDiv, type);
Aart Bikc071a012016-12-01 10:22:31 -0800519 } else if (instruction->IsRem()) {
Aart Bikdf7822e2016-12-06 10:05:30 -0800520 update = SolveOp(
Vladimir Markode4d1952022-03-07 09:29:40 +0000521 loop, phi, instruction, instruction->InputAt(0), instruction->InputAt(1), kRem, type);
Aart Bikc071a012016-12-01 10:22:31 -0800522 } else if (instruction->IsShl()) {
Aart Bikd0a022d2016-12-13 11:22:31 -0800523 HInstruction* mulc = GetShiftConstant(loop, instruction, /*initial*/ nullptr);
Aart Bikc071a012016-12-01 10:22:31 -0800524 if (mulc != nullptr) {
Vladimir Markode4d1952022-03-07 09:29:40 +0000525 update = SolveOp(loop, phi, instruction, instruction->InputAt(0), mulc, kMul, type);
Aart Bikc071a012016-12-01 10:22:31 -0800526 }
Aart Bikd0a022d2016-12-13 11:22:31 -0800527 } else if (instruction->IsShr() || instruction->IsUShr()) {
528 HInstruction* divc = GetShiftConstant(loop, instruction, initial);
529 if (divc != nullptr) {
Vladimir Markode4d1952022-03-07 09:29:40 +0000530 update = SolveOp(loop, phi, instruction, instruction->InputAt(0), divc, kDiv, type);
Aart Bikd0a022d2016-12-13 11:22:31 -0800531 }
Aart Bik7dc96932016-10-12 10:01:05 -0700532 } else if (instruction->IsXor()) {
Aart Bikdf7822e2016-12-06 10:05:30 -0800533 update = SolveOp(
Vladimir Markode4d1952022-03-07 09:29:40 +0000534 loop, phi, instruction, instruction->InputAt(0), instruction->InputAt(1), kXor, type);
Aart Bik639cc8c2016-10-18 13:03:31 -0700535 } else if (instruction->IsEqual()) {
Vladimir Markode4d1952022-03-07 09:29:40 +0000536 update = SolveTest(loop, phi, instruction, /*opposite_value=*/ 0, type);
Aart Bik639cc8c2016-10-18 13:03:31 -0700537 } else if (instruction->IsNotEqual()) {
Vladimir Markode4d1952022-03-07 09:29:40 +0000538 update = SolveTest(loop, phi, instruction, /*opposite_value=*/ 1, type);
Aart Bikd0a022d2016-12-13 11:22:31 -0800539 } else if (instruction->IsSelect()) {
Vladimir Markode4d1952022-03-07 09:29:40 +0000540 // Select acts like Phi.
541 update = SolvePhi(instruction, /*input_index=*/ 0, /*adjust_input_size=*/ 1, cycle);
Aart Bik0d345cf2016-03-16 10:49:38 -0700542 } else if (instruction->IsTypeConversion()) {
Vladimir Markode4d1952022-03-07 09:29:40 +0000543 update = SolveConversion(loop, phi, instruction->AsTypeConversion(), cycle, &type);
Aart Bik30efb4e2015-07-30 12:14:31 -0700544 }
545 if (update == nullptr) {
546 return;
547 }
Vladimir Markode4d1952022-03-07 09:29:40 +0000548 cycle.Put(instruction, update);
Aart Bik30efb4e2015-07-30 12:14:31 -0700549 }
550
Aart Bikf475bee2015-09-16 12:50:25 -0700551 // Success if all internal links received the same temporary meaning.
Vladimir Markode4d1952022-03-07 09:29:40 +0000552 InductionInfo* induction = SolvePhi(phi, /*input_index=*/ 1, /*adjust_input_size=*/ 0, cycle);
Aart Bikf475bee2015-09-16 12:50:25 -0700553 if (induction != nullptr) {
Aart Bike609b7c2015-08-27 13:46:58 -0700554 switch (induction->induction_class) {
555 case kInvariant:
Aart Bikc071a012016-12-01 10:22:31 -0800556 // Construct combined stride of the linear induction.
Vladimir Markode4d1952022-03-07 09:29:40 +0000557 induction = CreateInduction(kLinear, kNop, induction, initial, /*fetch*/ nullptr, type);
Aart Bikc071a012016-12-01 10:22:31 -0800558 FALLTHROUGH_INTENDED;
559 case kPolynomial:
560 case kGeometric:
Aart Bikdf7822e2016-12-06 10:05:30 -0800561 case kWrapAround:
Aart Bik22af3be2015-09-10 12:50:58 -0700562 // Classify first phi and then the rest of the cycle "on-demand".
563 // Statements are scanned in order.
Aart Bikc071a012016-12-01 10:22:31 -0800564 AssignInfo(loop, phi, induction);
Aart Bik22af3be2015-09-10 12:50:58 -0700565 for (size_t i = 1; i < size; i++) {
Vladimir Markode4d1952022-03-07 09:29:40 +0000566 ClassifyTrivial(loop, scc[i]);
Aart Bike609b7c2015-08-27 13:46:58 -0700567 }
568 break;
569 case kPeriodic:
Aart Bik22af3be2015-09-10 12:50:58 -0700570 // Classify all elements in the cycle with the found periodic induction while
571 // rotating each first element to the end. Lastly, phi is classified.
572 // Statements are scanned in reverse order.
573 for (size_t i = size - 1; i >= 1; i--) {
Vladimir Markode4d1952022-03-07 09:29:40 +0000574 AssignInfo(loop, scc[i], induction);
575 induction = RotatePeriodicInduction(induction->op_b, induction->op_a, type);
Aart Bike609b7c2015-08-27 13:46:58 -0700576 }
577 AssignInfo(loop, phi, induction);
578 break;
579 default:
580 break;
Aart Bik30efb4e2015-07-30 12:14:31 -0700581 }
582 }
583}
584
Aart Bike609b7c2015-08-27 13:46:58 -0700585HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::RotatePeriodicInduction(
586 InductionInfo* induction,
Vladimir Markode4d1952022-03-07 09:29:40 +0000587 InductionInfo* last,
588 DataType::Type type) {
Aart Bike609b7c2015-08-27 13:46:58 -0700589 // Rotates a periodic induction of the form
590 // (a, b, c, d, e)
591 // into
592 // (b, c, d, e, a)
593 // in preparation of assigning this to the previous variable in the sequence.
594 if (induction->induction_class == kInvariant) {
Aart Bikc071a012016-12-01 10:22:31 -0800595 return CreateInduction(kPeriodic,
596 kNop,
597 induction,
598 last,
599 /*fetch*/ nullptr,
Vladimir Markode4d1952022-03-07 09:29:40 +0000600 type);
Aart Bike609b7c2015-08-27 13:46:58 -0700601 }
Aart Bikc071a012016-12-01 10:22:31 -0800602 return CreateInduction(kPeriodic,
603 kNop,
604 induction->op_a,
Vladimir Markode4d1952022-03-07 09:29:40 +0000605 RotatePeriodicInduction(induction->op_b, last, type),
Aart Bikc071a012016-12-01 10:22:31 -0800606 /*fetch*/ nullptr,
Vladimir Markode4d1952022-03-07 09:29:40 +0000607 type);
Aart Bike609b7c2015-08-27 13:46:58 -0700608}
609
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000610HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::TransferPhi(
611 const HLoopInformation* loop,
612 HInstruction* phi,
613 size_t input_index,
614 size_t adjust_input_size) {
Aart Bikf475bee2015-09-16 12:50:25 -0700615 // Match all phi inputs from input_index onwards exactly.
Vladimir Markoe9004912016-06-16 16:50:52 +0100616 HInputsRef inputs = phi->GetInputs();
Vladimir Marko372f10e2016-05-17 16:30:10 +0100617 DCHECK_LT(input_index, inputs.size());
618 InductionInfo* a = LookupInfo(loop, inputs[input_index]);
Aart Bikd0a022d2016-12-13 11:22:31 -0800619 for (size_t i = input_index + 1, n = inputs.size() - adjust_input_size; i < n; i++) {
Vladimir Marko372f10e2016-05-17 16:30:10 +0100620 InductionInfo* b = LookupInfo(loop, inputs[i]);
Aart Bikf475bee2015-09-16 12:50:25 -0700621 if (!InductionEqual(a, b)) {
622 return nullptr;
623 }
Aart Bik30efb4e2015-07-30 12:14:31 -0700624 }
Aart Bikf475bee2015-09-16 12:50:25 -0700625 return a;
Aart Bik30efb4e2015-07-30 12:14:31 -0700626}
627
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000628HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::TransferAddSub(
629 const HBasicBlock* context,
630 const HLoopInformation* loop,
631 InductionInfo* a,
632 InductionInfo* b,
633 InductionOp op,
634 DataType::Type type) {
Aart Bikc071a012016-12-01 10:22:31 -0800635 // Transfer over an addition or subtraction: any invariant, linear, polynomial, geometric,
636 // wrap-around, or periodic can be combined with an invariant to yield a similar result.
Aart Bikdf7822e2016-12-06 10:05:30 -0800637 // Two linear or two polynomial inputs can be combined too. Other combinations fail.
Aart Bik30efb4e2015-07-30 12:14:31 -0700638 if (a != nullptr && b != nullptr) {
Aart Bike6bd0272016-12-16 13:57:52 -0800639 if (IsNarrowingLinear(a) || IsNarrowingLinear(b)) {
640 return nullptr; // no transfer
641 } else if (a->induction_class == kInvariant && b->induction_class == kInvariant) {
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000642 return CreateInvariantOp(context, loop, op, a, b); // direct invariant
Aart Bikdf7822e2016-12-06 10:05:30 -0800643 } else if ((a->induction_class == kLinear && b->induction_class == kLinear) ||
644 (a->induction_class == kPolynomial && b->induction_class == kPolynomial)) {
Aart Bik74da5292016-12-20 11:13:03 -0800645 // Rule induc(a, b) + induc(a', b') -> induc(a + a', b + b').
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000646 InductionInfo* new_a = TransferAddSub(context, loop, a->op_a, b->op_a, op, type);
647 InductionInfo* new_b = TransferAddSub(context, loop, a->op_b, b->op_b, op, type);
Vladimir Markode4d1952022-03-07 09:29:40 +0000648 if (new_a != nullptr && new_b != nullptr) {
649 return CreateInduction(a->induction_class, a->operation, new_a, new_b, a->fetch, type);
Aart Bik74da5292016-12-20 11:13:03 -0800650 }
Aart Bike609b7c2015-08-27 13:46:58 -0700651 } else if (a->induction_class == kInvariant) {
Aart Bik74da5292016-12-20 11:13:03 -0800652 // Rule a + induc(a', b') -> induc(a', a + b') or induc(a + a', a + b').
Aart Bike609b7c2015-08-27 13:46:58 -0700653 InductionInfo* new_a = b->op_a;
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000654 InductionInfo* new_b = TransferAddSub(context, loop, a, b->op_b, op, type);
Aart Bikc071a012016-12-01 10:22:31 -0800655 if (b->induction_class == kWrapAround || b->induction_class == kPeriodic) {
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000656 new_a = TransferAddSub(context, loop, a, new_a, op, type);
Aart Bike609b7c2015-08-27 13:46:58 -0700657 } else if (op == kSub) { // Negation required.
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000658 new_a = TransferNeg(context, loop, new_a, type);
Aart Bike609b7c2015-08-27 13:46:58 -0700659 }
Vladimir Markode4d1952022-03-07 09:29:40 +0000660 if (new_a != nullptr && new_b != nullptr) {
661 return CreateInduction(b->induction_class, b->operation, new_a, new_b, b->fetch, type);
Aart Bik74da5292016-12-20 11:13:03 -0800662 }
Aart Bike609b7c2015-08-27 13:46:58 -0700663 } else if (b->induction_class == kInvariant) {
Aart Bik74da5292016-12-20 11:13:03 -0800664 // Rule induc(a, b) + b' -> induc(a, b + b') or induc(a + b', b + b').
Aart Bike609b7c2015-08-27 13:46:58 -0700665 InductionInfo* new_a = a->op_a;
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000666 InductionInfo* new_b = TransferAddSub(context, loop, a->op_b, b, op, type);
Aart Bikc071a012016-12-01 10:22:31 -0800667 if (a->induction_class == kWrapAround || a->induction_class == kPeriodic) {
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000668 new_a = TransferAddSub(context, loop, new_a, b, op, type);
Aart Bike609b7c2015-08-27 13:46:58 -0700669 }
Vladimir Markode4d1952022-03-07 09:29:40 +0000670 if (new_a != nullptr && new_b != nullptr) {
671 return CreateInduction(a->induction_class, a->operation, new_a, new_b, a->fetch, type);
Aart Bik74da5292016-12-20 11:13:03 -0800672 }
Aart Bikc071a012016-12-01 10:22:31 -0800673 }
674 }
675 return nullptr;
676}
677
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000678HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::TransferNeg(
679 const HBasicBlock* context,
680 const HLoopInformation* loop,
681 InductionInfo* a,
682 DataType::Type type) {
Aart Bikc071a012016-12-01 10:22:31 -0800683 // Transfer over a unary negation: an invariant, linear, polynomial, geometric (mul),
684 // wrap-around, or periodic input yields a similar but negated induction as result.
685 if (a != nullptr) {
Aart Bike6bd0272016-12-16 13:57:52 -0800686 if (IsNarrowingLinear(a)) {
687 return nullptr; // no transfer
688 } else if (a->induction_class == kInvariant) {
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000689 return CreateInvariantOp(context, loop, kNeg, nullptr, a); // direct invariant
Aart Bikc071a012016-12-01 10:22:31 -0800690 } else if (a->induction_class != kGeometric || a->operation == kMul) {
Aart Bik74da5292016-12-20 11:13:03 -0800691 // Rule - induc(a, b) -> induc(-a, -b).
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000692 InductionInfo* new_a = TransferNeg(context, loop, a->op_a, type);
693 InductionInfo* new_b = TransferNeg(context, loop, a->op_b, type);
Aart Bik74da5292016-12-20 11:13:03 -0800694 if (new_a != nullptr && new_b != nullptr) {
Vladimir Markode4d1952022-03-07 09:29:40 +0000695 return CreateInduction(a->induction_class, a->operation, new_a, new_b, a->fetch, type);
Aart Bik74da5292016-12-20 11:13:03 -0800696 }
Aart Bik30efb4e2015-07-30 12:14:31 -0700697 }
698 }
699 return nullptr;
700}
701
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000702HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::TransferMul(
703 const HBasicBlock* context,
704 const HLoopInformation* loop,
705 InductionInfo* a,
706 InductionInfo* b,
707 DataType::Type type) {
Aart Bikc071a012016-12-01 10:22:31 -0800708 // Transfer over a multiplication: any invariant, linear, polynomial, geometric (mul),
709 // wrap-around, or periodic can be multiplied with an invariant to yield a similar
710 // but multiplied result. Two non-invariant inputs cannot be multiplied, however.
Aart Bik30efb4e2015-07-30 12:14:31 -0700711 if (a != nullptr && b != nullptr) {
Aart Bike6bd0272016-12-16 13:57:52 -0800712 if (IsNarrowingLinear(a) || IsNarrowingLinear(b)) {
713 return nullptr; // no transfer
714 } else if (a->induction_class == kInvariant && b->induction_class == kInvariant) {
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000715 return CreateInvariantOp(context, loop, kMul, a, b); // direct invariant
Aart Bikc071a012016-12-01 10:22:31 -0800716 } else if (a->induction_class == kInvariant && (b->induction_class != kGeometric ||
717 b->operation == kMul)) {
Aart Bik74da5292016-12-20 11:13:03 -0800718 // Rule a * induc(a', b') -> induc(a * a', b * b').
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000719 InductionInfo* new_a = TransferMul(context, loop, a, b->op_a, type);
720 InductionInfo* new_b = TransferMul(context, loop, a, b->op_b, type);
Aart Bik74da5292016-12-20 11:13:03 -0800721 if (new_a != nullptr && new_b != nullptr) {
Vladimir Markode4d1952022-03-07 09:29:40 +0000722 return CreateInduction(b->induction_class, b->operation, new_a, new_b, b->fetch, type);
Aart Bik74da5292016-12-20 11:13:03 -0800723 }
Aart Bikc071a012016-12-01 10:22:31 -0800724 } else if (b->induction_class == kInvariant && (a->induction_class != kGeometric ||
725 a->operation == kMul)) {
Aart Bik74da5292016-12-20 11:13:03 -0800726 // Rule induc(a, b) * b' -> induc(a * b', b * b').
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000727 InductionInfo* new_a = TransferMul(context, loop, a->op_a, b, type);
728 InductionInfo* new_b = TransferMul(context, loop, a->op_b, b, type);
Aart Bik74da5292016-12-20 11:13:03 -0800729 if (new_a != nullptr && new_b != nullptr) {
Vladimir Markode4d1952022-03-07 09:29:40 +0000730 return CreateInduction(a->induction_class, a->operation, new_a, new_b, a->fetch, type);
Aart Bik74da5292016-12-20 11:13:03 -0800731 }
Aart Bike609b7c2015-08-27 13:46:58 -0700732 }
733 }
734 return nullptr;
735}
736
Aart Bike6bd0272016-12-16 13:57:52 -0800737HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::TransferConversion(
738 InductionInfo* a,
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100739 DataType::Type from,
740 DataType::Type to) {
Aart Bik0d345cf2016-03-16 10:49:38 -0700741 if (a != nullptr) {
Aart Bike6bd0272016-12-16 13:57:52 -0800742 // Allow narrowing conversion on linear induction in certain cases:
743 // induction is already at narrow type, or can be made narrower.
744 if (IsNarrowingIntegralConversion(from, to) &&
745 a->induction_class == kLinear &&
746 (a->type == to || IsNarrowingIntegralConversion(a->type, to))) {
Aart Bik74da5292016-12-20 11:13:03 -0800747 return CreateInduction(kLinear, kNop, a->op_a, a->op_b, a->fetch, to);
Aart Bik0d345cf2016-03-16 10:49:38 -0700748 }
Aart Bik30efb4e2015-07-30 12:14:31 -0700749 }
750 return nullptr;
751}
752
Vladimir Markode4d1952022-03-07 09:29:40 +0000753HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::SolvePhi(
754 HInstruction* phi,
755 size_t input_index,
756 size_t adjust_input_size,
757 const ScopedArenaSafeMap<HInstruction*, InductionInfo*>& cycle) {
Aart Bikf475bee2015-09-16 12:50:25 -0700758 // Match all phi inputs from input_index onwards exactly.
Vladimir Markoe9004912016-06-16 16:50:52 +0100759 HInputsRef inputs = phi->GetInputs();
Vladimir Marko372f10e2016-05-17 16:30:10 +0100760 DCHECK_LT(input_index, inputs.size());
Vladimir Markode4d1952022-03-07 09:29:40 +0000761 auto ita = cycle.find(inputs[input_index]);
762 if (ita != cycle.end()) {
Aart Bikd0a022d2016-12-13 11:22:31 -0800763 for (size_t i = input_index + 1, n = inputs.size() - adjust_input_size; i < n; i++) {
Vladimir Markode4d1952022-03-07 09:29:40 +0000764 auto itb = cycle.find(inputs[i]);
765 if (itb == cycle.end() ||
Aart Bikf475bee2015-09-16 12:50:25 -0700766 !HInductionVarAnalysis::InductionEqual(ita->second, itb->second)) {
Aart Bik30efb4e2015-07-30 12:14:31 -0700767 return nullptr;
768 }
769 }
Aart Bikf475bee2015-09-16 12:50:25 -0700770 return ita->second;
771 }
772 return nullptr;
773}
774
775HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::SolvePhiAllInputs(
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000776 const HLoopInformation* loop,
Aart Bikf475bee2015-09-16 12:50:25 -0700777 HInstruction* entry_phi,
Vladimir Markode4d1952022-03-07 09:29:40 +0000778 HInstruction* phi,
779 const ScopedArenaSafeMap<HInstruction*, InductionInfo*>& cycle,
780 DataType::Type type) {
Aart Bikf475bee2015-09-16 12:50:25 -0700781 // Match all phi inputs.
Vladimir Markode4d1952022-03-07 09:29:40 +0000782 InductionInfo* match = SolvePhi(phi, /*input_index=*/ 0, /*adjust_input_size=*/ 0, cycle);
Aart Bikf475bee2015-09-16 12:50:25 -0700783 if (match != nullptr) {
784 return match;
Aart Bik30efb4e2015-07-30 12:14:31 -0700785 }
Aart Bik30efb4e2015-07-30 12:14:31 -0700786
Aart Bikf475bee2015-09-16 12:50:25 -0700787 // Otherwise, try to solve for a periodic seeded from phi onward.
788 // Only tight multi-statement cycles are considered in order to
789 // simplify rotating the periodic during the final classification.
790 if (phi->IsLoopHeaderPhi() && phi->InputCount() == 2) {
791 InductionInfo* a = LookupInfo(loop, phi->InputAt(0));
Aart Bike609b7c2015-08-27 13:46:58 -0700792 if (a != nullptr && a->induction_class == kInvariant) {
Aart Bikf475bee2015-09-16 12:50:25 -0700793 if (phi->InputAt(1) == entry_phi) {
794 InductionInfo* initial = LookupInfo(loop, entry_phi->InputAt(0));
Vladimir Markode4d1952022-03-07 09:29:40 +0000795 return CreateInduction(kPeriodic, kNop, a, initial, /*fetch*/ nullptr, type);
Aart Bike609b7c2015-08-27 13:46:58 -0700796 }
Vladimir Markode4d1952022-03-07 09:29:40 +0000797 InductionInfo* b = SolvePhi(phi, /*input_index=*/ 1, /*adjust_input_size=*/ 0, cycle);
Aart Bikf475bee2015-09-16 12:50:25 -0700798 if (b != nullptr && b->induction_class == kPeriodic) {
Vladimir Markode4d1952022-03-07 09:29:40 +0000799 return CreateInduction(kPeriodic, kNop, a, b, /*fetch*/ nullptr, type);
Aart Bik30efb4e2015-07-30 12:14:31 -0700800 }
801 }
802 }
Aart Bik30efb4e2015-07-30 12:14:31 -0700803 return nullptr;
804}
805
Vladimir Markode4d1952022-03-07 09:29:40 +0000806HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::SolveAddSub(
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000807 const HLoopInformation* loop,
Vladimir Markode4d1952022-03-07 09:29:40 +0000808 HInstruction* entry_phi,
809 HInstruction* instruction,
810 HInstruction* x,
811 HInstruction* y,
812 InductionOp op,
813 const ScopedArenaSafeMap<HInstruction*, InductionInfo*>& cycle,
814 DataType::Type type) {
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000815 const HBasicBlock* context = instruction->GetBlock();
Vladimir Markode4d1952022-03-07 09:29:40 +0000816 auto main_solve_add_sub = [&]() -> HInductionVarAnalysis::InductionInfo* {
817 // Solve within a cycle over an addition or subtraction.
818 InductionInfo* b = LookupInfo(loop, y);
819 if (b != nullptr) {
820 if (b->induction_class == kInvariant) {
821 // Adding or subtracting an invariant value, seeded from phi,
822 // keeps adding to the stride of the linear induction.
823 if (x == entry_phi) {
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000824 return (op == kAdd) ? b : CreateInvariantOp(context, loop, kNeg, nullptr, b);
Vladimir Markode4d1952022-03-07 09:29:40 +0000825 }
826 auto it = cycle.find(x);
827 if (it != cycle.end()) {
828 InductionInfo* a = it->second;
829 if (a->induction_class == kInvariant) {
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000830 return CreateInvariantOp(context, loop, op, a, b);
Vladimir Markode4d1952022-03-07 09:29:40 +0000831 }
832 }
833 } else if (b->induction_class == kLinear && b->type == type) {
834 // Solve within a tight cycle that adds a term that is already classified as a linear
835 // induction for a polynomial induction k = k + i (represented as sum over linear terms).
836 if (x == entry_phi &&
837 entry_phi->InputCount() == 2 &&
838 instruction == entry_phi->InputAt(1)) {
839 InductionInfo* initial = LookupInfo(loop, entry_phi->InputAt(0));
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000840 InductionInfo* new_a = op == kAdd ? b : TransferNeg(context, loop, b, type);
Vladimir Markode4d1952022-03-07 09:29:40 +0000841 if (new_a != nullptr) {
842 return CreateInduction(kPolynomial, kNop, new_a, initial, /*fetch*/ nullptr, type);
843 }
Aart Bikdf7822e2016-12-06 10:05:30 -0800844 }
845 }
Vladimir Markode4d1952022-03-07 09:29:40 +0000846 }
847 return nullptr;
848 };
849 HInductionVarAnalysis::InductionInfo* result = main_solve_add_sub();
850 if (result == nullptr) {
851 // Try some alternatives before failing.
852 if (op == kAdd) {
853 // Try the other way around for an addition.
854 std::swap(x, y);
855 result = main_solve_add_sub();
856 } else if (op == kSub) {
857 // Solve within a tight cycle that is formed by exactly two instructions,
858 // one phi and one update, for a periodic idiom of the form k = c - k.
859 if (y == entry_phi && entry_phi->InputCount() == 2 && instruction == entry_phi->InputAt(1)) {
860 InductionInfo* a = LookupInfo(loop, x);
861 if (a != nullptr && a->induction_class == kInvariant) {
862 InductionInfo* initial = LookupInfo(loop, entry_phi->InputAt(0));
863 result = CreateInduction(kPeriodic,
864 kNop,
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000865 CreateInvariantOp(context, loop, kSub, a, initial),
Vladimir Markode4d1952022-03-07 09:29:40 +0000866 initial,
867 /*fetch*/ nullptr,
868 type);
Aart Bik74da5292016-12-20 11:13:03 -0800869 }
Aart Bike609b7c2015-08-27 13:46:58 -0700870 }
Aart Bik30efb4e2015-07-30 12:14:31 -0700871 }
872 }
Vladimir Markode4d1952022-03-07 09:29:40 +0000873 return result;
Aart Bik30efb4e2015-07-30 12:14:31 -0700874}
875
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000876HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::SolveOp(const HLoopInformation* loop,
877 HInstruction* entry_phi,
878 HInstruction* instruction,
879 HInstruction* x,
880 HInstruction* y,
881 InductionOp op,
882 DataType::Type type) {
Aart Bikdf7822e2016-12-06 10:05:30 -0800883 // Solve within a tight cycle for a binary operation k = k op c or, for some op, k = c op k.
Aart Bik639cc8c2016-10-18 13:03:31 -0700884 if (entry_phi->InputCount() == 2 && instruction == entry_phi->InputAt(1)) {
Aart Bikdf7822e2016-12-06 10:05:30 -0800885 InductionInfo* c = nullptr;
Aart Bik639cc8c2016-10-18 13:03:31 -0700886 InductionInfo* b = LookupInfo(loop, y);
887 if (b != nullptr && b->induction_class == kInvariant && entry_phi == x) {
Aart Bikdf7822e2016-12-06 10:05:30 -0800888 c = b;
889 } else if (op != kDiv && op != kRem) {
890 InductionInfo* a = LookupInfo(loop, x);
891 if (a != nullptr && a->induction_class == kInvariant && entry_phi == y) {
892 c = a;
893 }
894 }
895 // Found suitable operand left or right?
896 if (c != nullptr) {
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000897 const HBasicBlock* context = instruction->GetBlock();
Aart Bikdf7822e2016-12-06 10:05:30 -0800898 InductionInfo* initial = LookupInfo(loop, entry_phi->InputAt(0));
899 switch (op) {
900 case kMul:
901 case kDiv:
902 // Restrict base of geometric induction to direct fetch.
903 if (c->operation == kFetch) {
904 return CreateInduction(kGeometric,
905 op,
906 initial,
Vladimir Markode4d1952022-03-07 09:29:40 +0000907 CreateConstant(0, type),
Aart Bikdf7822e2016-12-06 10:05:30 -0800908 c->fetch,
Vladimir Markode4d1952022-03-07 09:29:40 +0000909 type);
Igor Murashkin2ffb7032017-11-08 13:35:21 -0800910 }
Aart Bikdf7822e2016-12-06 10:05:30 -0800911 break;
912 case kRem:
913 // Idiomatic MOD wrap-around induction.
914 return CreateInduction(kWrapAround,
915 kNop,
916 initial,
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000917 CreateInvariantOp(context, loop, kRem, initial, c),
Aart Bikdf7822e2016-12-06 10:05:30 -0800918 /*fetch*/ nullptr,
Vladimir Markode4d1952022-03-07 09:29:40 +0000919 type);
Aart Bikdf7822e2016-12-06 10:05:30 -0800920 case kXor:
921 // Idiomatic XOR periodic induction.
922 return CreateInduction(kPeriodic,
923 kNop,
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000924 CreateInvariantOp(context, loop, kXor, initial, c),
Aart Bikdf7822e2016-12-06 10:05:30 -0800925 initial,
926 /*fetch*/ nullptr,
Vladimir Markode4d1952022-03-07 09:29:40 +0000927 type);
Aart Bikdf7822e2016-12-06 10:05:30 -0800928 default:
Andreas Gampef45d61c2017-06-07 10:29:33 -0700929 LOG(FATAL) << op;
930 UNREACHABLE();
Aart Bikdf7822e2016-12-06 10:05:30 -0800931 }
Aart Bik7dc96932016-10-12 10:01:05 -0700932 }
933 }
Aart Bik639cc8c2016-10-18 13:03:31 -0700934 return nullptr;
935}
936
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000937HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::SolveTest(const HLoopInformation* loop,
Aart Bik639cc8c2016-10-18 13:03:31 -0700938 HInstruction* entry_phi,
939 HInstruction* instruction,
Vladimir Markode4d1952022-03-07 09:29:40 +0000940 int64_t opposite_value,
941 DataType::Type type) {
Aart Bikc071a012016-12-01 10:22:31 -0800942 // Detect hidden XOR construction in x = (x == false) or x = (x != true).
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000943 const HBasicBlock* context = instruction->GetBlock();
Aart Bik639cc8c2016-10-18 13:03:31 -0700944 HInstruction* x = instruction->InputAt(0);
945 HInstruction* y = instruction->InputAt(1);
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000946 int64_t value = -1;
947 if (IsExact(context, loop, LookupInfo(loop, x), &value) && value == opposite_value) {
Vladimir Markode4d1952022-03-07 09:29:40 +0000948 return SolveOp(loop, entry_phi, instruction, graph_->GetIntConstant(1), y, kXor, type);
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000949 } else if (IsExact(context, loop, LookupInfo(loop, y), &value) && value == opposite_value) {
Vladimir Markode4d1952022-03-07 09:29:40 +0000950 return SolveOp(loop, entry_phi, instruction, x, graph_->GetIntConstant(1), kXor, type);
Aart Bik7dc96932016-10-12 10:01:05 -0700951 }
952 return nullptr;
953}
954
Aart Bike6bd0272016-12-16 13:57:52 -0800955HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::SolveConversion(
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000956 const HLoopInformation* loop,
Aart Bike6bd0272016-12-16 13:57:52 -0800957 HInstruction* entry_phi,
Vladimir Markode4d1952022-03-07 09:29:40 +0000958 HTypeConversion* conversion,
959 const ScopedArenaSafeMap<HInstruction*, InductionInfo*>& cycle,
960 /*inout*/ DataType::Type* type) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100961 DataType::Type from = conversion->GetInputType();
962 DataType::Type to = conversion->GetResultType();
Aart Bike6bd0272016-12-16 13:57:52 -0800963 // A narrowing conversion is allowed as *last* operation of the cycle of a linear induction
964 // with an initial value that fits the type, provided that the narrowest encountered type is
965 // recorded with the induction to account for the precision loss. The narrower induction does
966 // *not* transfer to any wider operations, however, since these may yield out-of-type values
967 if (entry_phi->InputCount() == 2 && conversion == entry_phi->InputAt(1)) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100968 int64_t min = DataType::MinValueOfIntegralType(to);
969 int64_t max = DataType::MaxValueOfIntegralType(to);
Aart Bike6bd0272016-12-16 13:57:52 -0800970 int64_t value = 0;
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000971 const HBasicBlock* context = conversion->GetBlock();
Aart Bike6bd0272016-12-16 13:57:52 -0800972 InductionInfo* initial = LookupInfo(loop, entry_phi->InputAt(0));
973 if (IsNarrowingIntegralConversion(from, to) &&
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000974 IsAtLeast(context, loop, initial, &value) && value >= min &&
975 IsAtMost(context, loop, initial, &value) && value <= max) {
Vladimir Markode4d1952022-03-07 09:29:40 +0000976 auto it = cycle.find(conversion->GetInput());
977 if (it != cycle.end() && it->second->induction_class == kInvariant) {
978 *type = to;
Aart Bike6bd0272016-12-16 13:57:52 -0800979 return it->second;
980 }
Aart Bik0d345cf2016-03-16 10:49:38 -0700981 }
982 }
983 return nullptr;
984}
985
Aart Bikceb06932017-11-13 10:31:17 -0800986//
987// Loop trip count analysis methods.
988//
989
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000990void HInductionVarAnalysis::VisitControl(const HLoopInformation* loop) {
Aart Bikd14c5952015-09-08 15:25:15 -0700991 HInstruction* control = loop->GetHeader()->GetLastInstruction();
992 if (control->IsIf()) {
993 HIf* ifs = control->AsIf();
994 HBasicBlock* if_true = ifs->IfTrueSuccessor();
995 HBasicBlock* if_false = ifs->IfFalseSuccessor();
996 HInstruction* if_expr = ifs->InputAt(0);
997 // Determine if loop has following structure in header.
998 // loop-header: ....
999 // if (condition) goto X
1000 if (if_expr->IsCondition()) {
1001 HCondition* condition = if_expr->AsCondition();
Vladimir Marko8d100ba2022-03-04 10:13:10 +00001002 const HBasicBlock* context = condition->GetBlock();
Aart Bikd14c5952015-09-08 15:25:15 -07001003 InductionInfo* a = LookupInfo(loop, condition->InputAt(0));
1004 InductionInfo* b = LookupInfo(loop, condition->InputAt(1));
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001005 DataType::Type type = ImplicitConversion(condition->InputAt(0)->GetType());
Aart Bik0d345cf2016-03-16 10:49:38 -07001006 // Determine if the loop control uses a known sequence on an if-exit (X outside) or on
1007 // an if-iterate (X inside), expressed as if-iterate when passed into VisitCondition().
1008 if (a == nullptr || b == nullptr) {
1009 return; // Loop control is not a sequence.
Aart Bikd14c5952015-09-08 15:25:15 -07001010 } else if (if_true->GetLoopInformation() != loop && if_false->GetLoopInformation() == loop) {
Vladimir Marko8d100ba2022-03-04 10:13:10 +00001011 VisitCondition(context, loop, if_false, a, b, type, condition->GetOppositeCondition());
Aart Bikd14c5952015-09-08 15:25:15 -07001012 } else if (if_true->GetLoopInformation() == loop && if_false->GetLoopInformation() != loop) {
Vladimir Marko8d100ba2022-03-04 10:13:10 +00001013 VisitCondition(context, loop, if_true, a, b, type, condition->GetCondition());
Aart Bikd14c5952015-09-08 15:25:15 -07001014 }
1015 }
1016 }
1017}
1018
Vladimir Marko8d100ba2022-03-04 10:13:10 +00001019void HInductionVarAnalysis::VisitCondition(const HBasicBlock* context,
1020 const HLoopInformation* loop,
Aart Bikceb06932017-11-13 10:31:17 -08001021 HBasicBlock* body,
Aart Bikd14c5952015-09-08 15:25:15 -07001022 InductionInfo* a,
1023 InductionInfo* b,
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001024 DataType::Type type,
Aart Bikd14c5952015-09-08 15:25:15 -07001025 IfCondition cmp) {
1026 if (a->induction_class == kInvariant && b->induction_class == kLinear) {
Aart Bikf475bee2015-09-16 12:50:25 -07001027 // 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 -07001028 switch (cmp) {
Vladimir Marko8d100ba2022-03-04 10:13:10 +00001029 case kCondLT: VisitCondition(context, loop, body, b, a, type, kCondGT); break;
1030 case kCondLE: VisitCondition(context, loop, body, b, a, type, kCondGE); break;
1031 case kCondGT: VisitCondition(context, loop, body, b, a, type, kCondLT); break;
1032 case kCondGE: VisitCondition(context, loop, body, b, a, type, kCondLE); break;
1033 case kCondNE: VisitCondition(context, loop, body, b, a, type, kCondNE); break;
Aart Bikd14c5952015-09-08 15:25:15 -07001034 default: break;
1035 }
1036 } else if (a->induction_class == kLinear && b->induction_class == kInvariant) {
Aart Bikf475bee2015-09-16 12:50:25 -07001037 // Analyze condition with induction at left-hand-side (e.g. i < U).
Aart Bik9401f532015-09-28 16:25:56 -07001038 InductionInfo* lower_expr = a->op_b;
1039 InductionInfo* upper_expr = b;
Aart Bik97412c922016-02-19 20:14:38 -08001040 InductionInfo* stride_expr = a->op_a;
Aart Bikceb06932017-11-13 10:31:17 -08001041 // Test for constant stride and integral condition.
Aart Bik9401f532015-09-28 16:25:56 -07001042 int64_t stride_value = 0;
Vladimir Marko8d100ba2022-03-04 10:13:10 +00001043 if (!IsExact(context, loop, stride_expr, &stride_value)) {
Aart Bikceb06932017-11-13 10:31:17 -08001044 return; // unknown stride
1045 } else if (type != DataType::Type::kInt32 && type != DataType::Type::kInt64) {
1046 return; // not integral
Aart Bikf475bee2015-09-16 12:50:25 -07001047 }
Aart Bikceb06932017-11-13 10:31:17 -08001048 // Since loops with a i != U condition will not be normalized by the method below, first
1049 // try to rewrite a break-loop with terminating condition i != U into an equivalent loop
1050 // with non-strict end condition i <= U or i >= U if such a rewriting is possible and safe.
Vladimir Marko8d100ba2022-03-04 10:13:10 +00001051 if (cmp == kCondNE && RewriteBreakLoop(context, loop, body, stride_value, type)) {
Aart Bikceb06932017-11-13 10:31:17 -08001052 cmp = stride_value > 0 ? kCondLE : kCondGE;
1053 }
1054 // If this rewriting failed, try to rewrite condition i != U into strict end condition i < U
1055 // or i > U if this end condition is reached exactly (tested by verifying if the loop has a
1056 // unit stride and the non-strict condition would be always taken).
Vladimir Marko8d100ba2022-03-04 10:13:10 +00001057 if (cmp == kCondNE &&
1058 ((stride_value == +1 && IsTaken(context, loop, lower_expr, upper_expr, kCondLE)) ||
1059 (stride_value == -1 && IsTaken(context, loop, lower_expr, upper_expr, kCondGE)))) {
Aart Bik9401f532015-09-28 16:25:56 -07001060 cmp = stride_value > 0 ? kCondLT : kCondGT;
Aart Bikd14c5952015-09-08 15:25:15 -07001061 }
Aart Bikceb06932017-11-13 10:31:17 -08001062 // A mismatch between the type of condition and the induction is only allowed if the,
1063 // necessarily narrower, induction range fits the narrower control.
1064 if (type != a->type &&
Vladimir Marko8d100ba2022-03-04 10:13:10 +00001065 !FitsNarrowerControl(context, loop, lower_expr, upper_expr, stride_value, a->type, cmp)) {
Aart Bik0d345cf2016-03-16 10:49:38 -07001066 return; // mismatched type
1067 }
Aart Bikf475bee2015-09-16 12:50:25 -07001068 // Normalize a linear loop control with a nonzero stride:
1069 // stride > 0, either i < U or i <= U
1070 // stride < 0, either i > U or i >= U
Aart Bikf475bee2015-09-16 12:50:25 -07001071 if ((stride_value > 0 && (cmp == kCondLT || cmp == kCondLE)) ||
1072 (stride_value < 0 && (cmp == kCondGT || cmp == kCondGE))) {
Vladimir Marko8d100ba2022-03-04 10:13:10 +00001073 VisitTripCount(context, loop, lower_expr, upper_expr, stride_expr, stride_value, type, cmp);
Aart Bikf475bee2015-09-16 12:50:25 -07001074 }
Aart Bikd14c5952015-09-08 15:25:15 -07001075 }
1076}
1077
Vladimir Marko8d100ba2022-03-04 10:13:10 +00001078void HInductionVarAnalysis::VisitTripCount(const HBasicBlock* context,
1079 const HLoopInformation* loop,
Aart Bik9401f532015-09-28 16:25:56 -07001080 InductionInfo* lower_expr,
1081 InductionInfo* upper_expr,
Aart Bik97412c922016-02-19 20:14:38 -08001082 InductionInfo* stride_expr,
Aart Bik9401f532015-09-28 16:25:56 -07001083 int64_t stride_value,
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001084 DataType::Type type,
Aart Bikf475bee2015-09-16 12:50:25 -07001085 IfCondition cmp) {
Aart Bikd14c5952015-09-08 15:25:15 -07001086 // Any loop of the general form:
1087 //
1088 // for (i = L; i <= U; i += S) // S > 0
1089 // or for (i = L; i >= U; i += S) // S < 0
1090 // .. i ..
1091 //
1092 // can be normalized into:
1093 //
1094 // for (n = 0; n < TC; n++) // where TC = (U + S - L) / S
1095 // .. L + S * n ..
1096 //
Aart Bik9401f532015-09-28 16:25:56 -07001097 // taking the following into consideration:
Aart Bikd14c5952015-09-08 15:25:15 -07001098 //
Aart Bik9401f532015-09-28 16:25:56 -07001099 // (1) Using the same precision, the TC (trip-count) expression should be interpreted as
1100 // an unsigned entity, for example, as in the following loop that uses the full range:
1101 // for (int i = INT_MIN; i < INT_MAX; i++) // TC = UINT_MAX
1102 // (2) The TC is only valid if the loop is taken, otherwise TC = 0, as in:
Aart Bikd5cc6832016-06-22 16:34:46 -07001103 // for (int i = 12; i < U; i++) // TC = 0 when U <= 12
Aart Bik9401f532015-09-28 16:25:56 -07001104 // If this cannot be determined at compile-time, the TC is only valid within the
Aart Bik22f05872015-10-27 15:56:28 -07001105 // loop-body proper, not the loop-header unless enforced with an explicit taken-test.
Aart Bik9401f532015-09-28 16:25:56 -07001106 // (3) The TC is only valid if the loop is finite, otherwise TC has no value, as in:
1107 // for (int i = 0; i <= U; i++) // TC = Inf when U = INT_MAX
1108 // If this cannot be determined at compile-time, the TC is only valid when enforced
Aart Bik22f05872015-10-27 15:56:28 -07001109 // with an explicit finite-test.
Aart Bik9401f532015-09-28 16:25:56 -07001110 // (4) For loops which early-exits, the TC forms an upper bound, as in:
1111 // for (int i = 0; i < 10 && ....; i++) // TC <= 10
Aart Bik22f05872015-10-27 15:56:28 -07001112 InductionInfo* trip_count = upper_expr;
Vladimir Marko8d100ba2022-03-04 10:13:10 +00001113 const bool is_taken = IsTaken(context, loop, lower_expr, upper_expr, cmp);
1114 const bool is_finite = IsFinite(context, loop, upper_expr, stride_value, type, cmp);
Aart Bik9401f532015-09-28 16:25:56 -07001115 const bool cancels = (cmp == kCondLT || cmp == kCondGT) && std::abs(stride_value) == 1;
Aart Bikd14c5952015-09-08 15:25:15 -07001116 if (!cancels) {
1117 // Convert exclusive integral inequality into inclusive integral inequality,
1118 // viz. condition i < U is i <= U - 1 and condition i > U is i >= U + 1.
Aart Bikf475bee2015-09-16 12:50:25 -07001119 if (cmp == kCondLT) {
Vladimir Marko8d100ba2022-03-04 10:13:10 +00001120 trip_count = CreateInvariantOp(context, loop, kSub, trip_count, CreateConstant(1, type));
Aart Bikf475bee2015-09-16 12:50:25 -07001121 } else if (cmp == kCondGT) {
Vladimir Marko8d100ba2022-03-04 10:13:10 +00001122 trip_count = CreateInvariantOp(context, loop, kAdd, trip_count, CreateConstant(1, type));
Aart Bikd14c5952015-09-08 15:25:15 -07001123 }
1124 // Compensate for stride.
Vladimir Marko8d100ba2022-03-04 10:13:10 +00001125 trip_count = CreateInvariantOp(context, loop, kAdd, trip_count, stride_expr);
Aart Bikd14c5952015-09-08 15:25:15 -07001126 }
Vladimir Marko8d100ba2022-03-04 10:13:10 +00001127 trip_count = CreateInvariantOp(context, loop, kSub, trip_count, lower_expr);
1128 trip_count = CreateInvariantOp(context, loop, kDiv, trip_count, stride_expr);
Aart Bikd14c5952015-09-08 15:25:15 -07001129 // Assign the trip-count expression to the loop control. Clients that use the information
Aart Bik9401f532015-09-28 16:25:56 -07001130 // should be aware that the expression is only valid under the conditions listed above.
Aart Bik22f05872015-10-27 15:56:28 -07001131 InductionOp tcKind = kTripCountInBodyUnsafe; // needs both tests
Aart Bik9401f532015-09-28 16:25:56 -07001132 if (is_taken && is_finite) {
Aart Bik22f05872015-10-27 15:56:28 -07001133 tcKind = kTripCountInLoop; // needs neither test
Aart Bik9401f532015-09-28 16:25:56 -07001134 } else if (is_finite) {
Aart Bik22f05872015-10-27 15:56:28 -07001135 tcKind = kTripCountInBody; // needs taken-test
Aart Bik9401f532015-09-28 16:25:56 -07001136 } else if (is_taken) {
Aart Bik22f05872015-10-27 15:56:28 -07001137 tcKind = kTripCountInLoopUnsafe; // needs finite-test
Aart Bik9401f532015-09-28 16:25:56 -07001138 }
Aart Bik22f05872015-10-27 15:56:28 -07001139 InductionOp op = kNop;
1140 switch (cmp) {
1141 case kCondLT: op = kLT; break;
1142 case kCondLE: op = kLE; break;
1143 case kCondGT: op = kGT; break;
1144 case kCondGE: op = kGE; break;
1145 default: LOG(FATAL) << "CONDITION UNREACHABLE";
1146 }
Aart Bik009cace2016-09-16 10:15:19 -07001147 // Associate trip count with control instruction, rather than the condition (even
1148 // though it's its use) since former provides a convenient use-free placeholder.
1149 HInstruction* control = loop->GetHeader()->GetLastInstruction();
Vladimir Marko8d100ba2022-03-04 10:13:10 +00001150 InductionInfo* taken_test = CreateInvariantOp(context, loop, op, lower_expr, upper_expr);
Aart Bik009cace2016-09-16 10:15:19 -07001151 DCHECK(control->IsIf());
1152 AssignInfo(loop, control, CreateTripCount(tcKind, trip_count, taken_test, type));
Aart Bik9401f532015-09-28 16:25:56 -07001153}
1154
Vladimir Marko8d100ba2022-03-04 10:13:10 +00001155bool HInductionVarAnalysis::IsTaken(const HBasicBlock* context,
1156 const HLoopInformation* loop,
1157 InductionInfo* lower_expr,
Aart Bik9401f532015-09-28 16:25:56 -07001158 InductionInfo* upper_expr,
1159 IfCondition cmp) {
1160 int64_t lower_value;
1161 int64_t upper_value;
Aart Bik97412c922016-02-19 20:14:38 -08001162 switch (cmp) {
1163 case kCondLT:
Vladimir Marko8d100ba2022-03-04 10:13:10 +00001164 return IsAtMost(context, loop, lower_expr, &lower_value)
1165 && IsAtLeast(context, loop, upper_expr, &upper_value)
Aart Bik97412c922016-02-19 20:14:38 -08001166 && lower_value < upper_value;
1167 case kCondLE:
Vladimir Marko8d100ba2022-03-04 10:13:10 +00001168 return IsAtMost(context, loop, lower_expr, &lower_value)
1169 && IsAtLeast(context, loop, upper_expr, &upper_value)
Aart Bik97412c922016-02-19 20:14:38 -08001170 && lower_value <= upper_value;
1171 case kCondGT:
Vladimir Marko8d100ba2022-03-04 10:13:10 +00001172 return IsAtLeast(context, loop, lower_expr, &lower_value)
1173 && IsAtMost(context, loop, upper_expr, &upper_value)
Aart Bik97412c922016-02-19 20:14:38 -08001174 && lower_value > upper_value;
1175 case kCondGE:
Vladimir Marko8d100ba2022-03-04 10:13:10 +00001176 return IsAtLeast(context, loop, lower_expr, &lower_value)
1177 && IsAtMost(context, loop, upper_expr, &upper_value)
Aart Bik97412c922016-02-19 20:14:38 -08001178 && lower_value >= upper_value;
1179 default:
1180 LOG(FATAL) << "CONDITION UNREACHABLE";
Elliott Hughesc1896c92018-11-29 11:33:18 -08001181 UNREACHABLE();
Aart Bik9401f532015-09-28 16:25:56 -07001182 }
Aart Bik9401f532015-09-28 16:25:56 -07001183}
1184
Vladimir Marko8d100ba2022-03-04 10:13:10 +00001185bool HInductionVarAnalysis::IsFinite(const HBasicBlock* context,
1186 const HLoopInformation* loop,
1187 InductionInfo* upper_expr,
Aart Bik9401f532015-09-28 16:25:56 -07001188 int64_t stride_value,
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001189 DataType::Type type,
Aart Bik9401f532015-09-28 16:25:56 -07001190 IfCondition cmp) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001191 int64_t min = DataType::MinValueOfIntegralType(type);
1192 int64_t max = DataType::MaxValueOfIntegralType(type);
Aart Bik9401f532015-09-28 16:25:56 -07001193 // Some rules under which it is certain at compile-time that the loop is finite.
1194 int64_t value;
1195 switch (cmp) {
1196 case kCondLT:
1197 return stride_value == 1 ||
Vladimir Marko8d100ba2022-03-04 10:13:10 +00001198 (IsAtMost(context, loop, upper_expr, &value) && value <= (max - stride_value + 1));
Aart Bik9401f532015-09-28 16:25:56 -07001199 case kCondLE:
Vladimir Marko8d100ba2022-03-04 10:13:10 +00001200 return (IsAtMost(context, loop, upper_expr, &value) && value <= (max - stride_value));
Aart Bik9401f532015-09-28 16:25:56 -07001201 case kCondGT:
1202 return stride_value == -1 ||
Vladimir Marko8d100ba2022-03-04 10:13:10 +00001203 (IsAtLeast(context, loop, upper_expr, &value) && value >= (min - stride_value - 1));
Aart Bik9401f532015-09-28 16:25:56 -07001204 case kCondGE:
Vladimir Marko8d100ba2022-03-04 10:13:10 +00001205 return (IsAtLeast(context, loop, upper_expr, &value) && value >= (min - stride_value));
Aart Bike9f37602015-10-09 11:15:55 -07001206 default:
1207 LOG(FATAL) << "CONDITION UNREACHABLE";
Elliott Hughesc1896c92018-11-29 11:33:18 -08001208 UNREACHABLE();
Aart Bik9401f532015-09-28 16:25:56 -07001209 }
Aart Bikd14c5952015-09-08 15:25:15 -07001210}
1211
Vladimir Marko8d100ba2022-03-04 10:13:10 +00001212bool HInductionVarAnalysis::FitsNarrowerControl(const HBasicBlock* context,
1213 const HLoopInformation* loop,
1214 InductionInfo* lower_expr,
Aart Bik0d345cf2016-03-16 10:49:38 -07001215 InductionInfo* upper_expr,
1216 int64_t stride_value,
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001217 DataType::Type type,
Aart Bik0d345cf2016-03-16 10:49:38 -07001218 IfCondition cmp) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001219 int64_t min = DataType::MinValueOfIntegralType(type);
1220 int64_t max = DataType::MaxValueOfIntegralType(type);
Aart Bik0d345cf2016-03-16 10:49:38 -07001221 // Inclusive test need one extra.
1222 if (stride_value != 1 && stride_value != -1) {
1223 return false; // non-unit stride
1224 } else if (cmp == kCondLE) {
1225 max--;
1226 } else if (cmp == kCondGE) {
1227 min++;
1228 }
1229 // Do both bounds fit the range?
Vladimir Marko0e2f2ff2016-03-22 12:31:54 +00001230 int64_t value = 0;
Vladimir Marko8d100ba2022-03-04 10:13:10 +00001231 return IsAtLeast(context, loop, lower_expr, &value) && value >= min &&
1232 IsAtMost(context, loop, lower_expr, &value) && value <= max &&
1233 IsAtLeast(context, loop, upper_expr, &value) && value >= min &&
1234 IsAtMost(context, loop, upper_expr, &value) && value <= max;
Aart Bik0d345cf2016-03-16 10:49:38 -07001235}
1236
Vladimir Marko8d100ba2022-03-04 10:13:10 +00001237bool HInductionVarAnalysis::RewriteBreakLoop(const HBasicBlock* context,
1238 const HLoopInformation* loop,
Aart Bikceb06932017-11-13 10:31:17 -08001239 HBasicBlock* body,
1240 int64_t stride_value,
1241 DataType::Type type) {
1242 // Only accept unit stride.
1243 if (std::abs(stride_value) != 1) {
1244 return false;
1245 }
1246 // Simple terminating i != U condition, used nowhere else.
1247 HIf* ifs = loop->GetHeader()->GetLastInstruction()->AsIf();
1248 HInstruction* cond = ifs->InputAt(0);
1249 if (ifs->GetPrevious() != cond || !cond->HasOnlyOneNonEnvironmentUse()) {
1250 return false;
1251 }
1252 int c = LookupInfo(loop, cond->InputAt(0))->induction_class == kLinear ? 0 : 1;
1253 HInstruction* index = cond->InputAt(c);
1254 HInstruction* upper = cond->InputAt(1 - c);
1255 // Safe to rewrite into i <= U?
1256 IfCondition cmp = stride_value > 0 ? kCondLE : kCondGE;
Vladimir Marko8d100ba2022-03-04 10:13:10 +00001257 if (!index->IsPhi() ||
1258 !IsFinite(context, loop, LookupInfo(loop, upper), stride_value, type, cmp)) {
Aart Bikceb06932017-11-13 10:31:17 -08001259 return false;
1260 }
1261 // Body consists of update to index i only, used nowhere else.
1262 if (body->GetSuccessors().size() != 1 ||
1263 body->GetSingleSuccessor() != loop->GetHeader() ||
1264 !body->GetPhis().IsEmpty() ||
1265 body->GetInstructions().IsEmpty() ||
1266 body->GetFirstInstruction() != index->InputAt(1) ||
1267 !body->GetFirstInstruction()->HasOnlyOneNonEnvironmentUse() ||
1268 !body->GetFirstInstruction()->GetNext()->IsGoto()) {
1269 return false;
1270 }
1271 // Always taken or guarded by enclosing condition.
Vladimir Marko8d100ba2022-03-04 10:13:10 +00001272 if (!IsTaken(context, loop, LookupInfo(loop, index)->op_b, LookupInfo(loop, upper), cmp) &&
Aart Bikceb06932017-11-13 10:31:17 -08001273 !IsGuardedBy(loop, cmp, index->InputAt(0), upper)) {
1274 return false;
1275 }
1276 // Test if break-loop body can be written, and do so on success.
1277 if (RewriteBreakLoopBody(loop, body, cond, index, upper, /*rewrite*/ false)) {
1278 RewriteBreakLoopBody(loop, body, cond, index, upper, /*rewrite*/ true);
1279 } else {
1280 return false;
1281 }
1282 // Rewrite condition in HIR.
1283 if (ifs->IfTrueSuccessor() != body) {
1284 cmp = (cmp == kCondLE) ? kCondGT : kCondLT;
1285 }
1286 HInstruction* rep = nullptr;
1287 switch (cmp) {
1288 case kCondLT: rep = new (graph_->GetAllocator()) HLessThan(index, upper); break;
1289 case kCondGT: rep = new (graph_->GetAllocator()) HGreaterThan(index, upper); break;
1290 case kCondLE: rep = new (graph_->GetAllocator()) HLessThanOrEqual(index, upper); break;
1291 case kCondGE: rep = new (graph_->GetAllocator()) HGreaterThanOrEqual(index, upper); break;
1292 default: LOG(FATAL) << cmp; UNREACHABLE();
1293 }
1294 loop->GetHeader()->ReplaceAndRemoveInstructionWith(cond, rep);
1295 return true;
1296}
1297
1298//
1299// Helper methods.
1300//
1301
Vladimir Marko8d100ba2022-03-04 10:13:10 +00001302void HInductionVarAnalysis::AssignInfo(const HLoopInformation* loop,
Aart Bik30efb4e2015-07-30 12:14:31 -07001303 HInstruction* instruction,
1304 InductionInfo* info) {
Aart Bike609b7c2015-08-27 13:46:58 -07001305 auto it = induction_.find(loop);
1306 if (it == induction_.end()) {
1307 it = induction_.Put(loop,
1308 ArenaSafeMap<HInstruction*, InductionInfo*>(
Vladimir Marko5233f932015-09-29 19:01:15 +01001309 std::less<HInstruction*>(),
Vladimir Markoca6fff82017-10-03 14:49:14 +01001310 graph_->GetAllocator()->Adapter(kArenaAllocInductionVarAnalysis)));
Aart Bike609b7c2015-08-27 13:46:58 -07001311 }
1312 it->second.Put(instruction, info);
Aart Bik30efb4e2015-07-30 12:14:31 -07001313}
1314
Vladimir Marko8d100ba2022-03-04 10:13:10 +00001315HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::LookupInfo(
1316 const HLoopInformation* loop,
1317 HInstruction* instruction) {
Aart Bike609b7c2015-08-27 13:46:58 -07001318 auto it = induction_.find(loop);
1319 if (it != induction_.end()) {
1320 auto loop_it = it->second.find(instruction);
1321 if (loop_it != it->second.end()) {
1322 return loop_it->second;
1323 }
Aart Bik30efb4e2015-07-30 12:14:31 -07001324 }
Mingyao Yang4b467ed2015-11-19 17:04:22 -08001325 if (loop->IsDefinedOutOfTheLoop(instruction)) {
Aart Bik471a2032015-09-04 18:22:11 -07001326 InductionInfo* info = CreateInvariantFetch(instruction);
Aart Bike609b7c2015-08-27 13:46:58 -07001327 AssignInfo(loop, instruction, info);
1328 return info;
1329 }
1330 return nullptr;
Aart Bik30efb4e2015-07-30 12:14:31 -07001331}
1332
Aart Bikd14c5952015-09-08 15:25:15 -07001333HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::CreateConstant(int64_t value,
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001334 DataType::Type type) {
Aart Bikc071a012016-12-01 10:22:31 -08001335 HInstruction* constant;
1336 switch (type) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001337 case DataType::Type::kFloat64: constant = graph_->GetDoubleConstant(value); break;
1338 case DataType::Type::kFloat32: constant = graph_->GetFloatConstant(value); break;
1339 case DataType::Type::kInt64: constant = graph_->GetLongConstant(value); break;
1340 default: constant = graph_->GetIntConstant(value); break;
Aart Bikd14c5952015-09-08 15:25:15 -07001341 }
Aart Bikc071a012016-12-01 10:22:31 -08001342 return CreateInvariantFetch(constant);
Aart Bikd14c5952015-09-08 15:25:15 -07001343}
1344
Aart Bik471a2032015-09-04 18:22:11 -07001345HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::CreateSimplifiedInvariant(
Vladimir Marko8d100ba2022-03-04 10:13:10 +00001346 const HBasicBlock* context,
1347 const HLoopInformation* loop,
Aart Bik471a2032015-09-04 18:22:11 -07001348 InductionOp op,
1349 InductionInfo* a,
1350 InductionInfo* b) {
1351 // Perform some light-weight simplifications during construction of a new invariant.
1352 // This often safes memory and yields a more concise representation of the induction.
1353 // More exhaustive simplifications are done by later phases once induction nodes are
1354 // translated back into HIR code (e.g. by loop optimizations or BCE).
1355 int64_t value = -1;
Vladimir Marko8d100ba2022-03-04 10:13:10 +00001356 if (IsExact(context, loop, a, &value)) {
Aart Bik471a2032015-09-04 18:22:11 -07001357 if (value == 0) {
Aart Bik7dc96932016-10-12 10:01:05 -07001358 // Simplify 0 + b = b, 0 ^ b = b, 0 * b = 0.
1359 if (op == kAdd || op == kXor) {
Aart Bik471a2032015-09-04 18:22:11 -07001360 return b;
1361 } else if (op == kMul) {
1362 return a;
1363 }
Aart Bikd14c5952015-09-08 15:25:15 -07001364 } else if (op == kMul) {
1365 // Simplify 1 * b = b, -1 * b = -b
1366 if (value == 1) {
1367 return b;
1368 } else if (value == -1) {
Vladimir Marko8d100ba2022-03-04 10:13:10 +00001369 return CreateSimplifiedInvariant(context, loop, kNeg, nullptr, b);
Aart Bikd14c5952015-09-08 15:25:15 -07001370 }
Aart Bik471a2032015-09-04 18:22:11 -07001371 }
1372 }
Vladimir Marko8d100ba2022-03-04 10:13:10 +00001373 if (IsExact(context, loop, b, &value)) {
Aart Bik471a2032015-09-04 18:22:11 -07001374 if (value == 0) {
Aart Bik7dc96932016-10-12 10:01:05 -07001375 // Simplify a + 0 = a, a - 0 = a, a ^ 0 = a, a * 0 = 0, -0 = 0.
1376 if (op == kAdd || op == kSub || op == kXor) {
Aart Bik471a2032015-09-04 18:22:11 -07001377 return a;
1378 } else if (op == kMul || op == kNeg) {
1379 return b;
1380 }
Aart Bikd14c5952015-09-08 15:25:15 -07001381 } else if (op == kMul || op == kDiv) {
1382 // Simplify a * 1 = a, a / 1 = a, a * -1 = -a, a / -1 = -a
1383 if (value == 1) {
1384 return a;
1385 } else if (value == -1) {
Vladimir Marko8d100ba2022-03-04 10:13:10 +00001386 return CreateSimplifiedInvariant(context, loop, kNeg, nullptr, a);
Aart Bikd14c5952015-09-08 15:25:15 -07001387 }
Aart Bik471a2032015-09-04 18:22:11 -07001388 }
1389 } else if (b->operation == kNeg) {
Aart Bikd14c5952015-09-08 15:25:15 -07001390 // Simplify a + (-b) = a - b, a - (-b) = a + b, -(-b) = b.
1391 if (op == kAdd) {
Vladimir Marko8d100ba2022-03-04 10:13:10 +00001392 return CreateSimplifiedInvariant(context, loop, kSub, a, b->op_b);
Aart Bikd14c5952015-09-08 15:25:15 -07001393 } else if (op == kSub) {
Vladimir Marko8d100ba2022-03-04 10:13:10 +00001394 return CreateSimplifiedInvariant(context, loop, kAdd, a, b->op_b);
Aart Bikd14c5952015-09-08 15:25:15 -07001395 } else if (op == kNeg) {
1396 return b->op_b;
Aart Bik471a2032015-09-04 18:22:11 -07001397 }
Aart Bik7d57d7f2015-12-09 14:39:48 -08001398 } else if (b->operation == kSub) {
1399 // Simplify - (a - b) = b - a.
1400 if (op == kNeg) {
Vladimir Marko8d100ba2022-03-04 10:13:10 +00001401 return CreateSimplifiedInvariant(context, loop, kSub, b->op_b, b->op_a);
Aart Bik7d57d7f2015-12-09 14:39:48 -08001402 }
Aart Bik471a2032015-09-04 18:22:11 -07001403 }
Vladimir Markoca6fff82017-10-03 14:49:14 +01001404 return new (graph_->GetAllocator()) InductionInfo(
Aart Bike6bd0272016-12-16 13:57:52 -08001405 kInvariant, op, a, b, nullptr, ImplicitConversion(b->type));
Aart Bik471a2032015-09-04 18:22:11 -07001406}
1407
Vladimir Marko8d100ba2022-03-04 10:13:10 +00001408HInstruction* HInductionVarAnalysis::GetShiftConstant(const HLoopInformation* loop,
Aart Bikd0a022d2016-12-13 11:22:31 -08001409 HInstruction* instruction,
1410 InductionInfo* initial) {
1411 DCHECK(instruction->IsShl() || instruction->IsShr() || instruction->IsUShr());
Vladimir Marko8d100ba2022-03-04 10:13:10 +00001412 const HBasicBlock* context = instruction->GetBlock();
Aart Bikd0a022d2016-12-13 11:22:31 -08001413 // Shift-rights are only the same as division for non-negative initial inputs.
1414 // Otherwise we would round incorrectly.
1415 if (initial != nullptr) {
1416 int64_t value = -1;
Vladimir Marko8d100ba2022-03-04 10:13:10 +00001417 if (!IsAtLeast(context, loop, initial, &value) || value < 0) {
Aart Bikd0a022d2016-12-13 11:22:31 -08001418 return nullptr;
1419 }
1420 }
1421 // Obtain the constant needed to treat shift as equivalent multiplication or division.
1422 // This yields an existing instruction if the constant is already there. Otherwise, this
1423 // has a side effect on the HIR. The restriction on the shift factor avoids generating a
1424 // negative constant (viz. 1 << 31 and 1L << 63 set the sign bit). The code assumes that
1425 // generalization for shift factors outside [0,32) and [0,64) ranges is done earlier.
Aart Bikc071a012016-12-01 10:22:31 -08001426 InductionInfo* b = LookupInfo(loop, instruction->InputAt(1));
1427 int64_t value = -1;
Vladimir Marko8d100ba2022-03-04 10:13:10 +00001428 if (IsExact(context, loop, b, &value)) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001429 DataType::Type type = instruction->InputAt(0)->GetType();
1430 if (type == DataType::Type::kInt32 && 0 <= value && value < 31) {
Aart Bikc071a012016-12-01 10:22:31 -08001431 return graph_->GetIntConstant(1 << value);
1432 }
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001433 if (type == DataType::Type::kInt64 && 0 <= value && value < 63) {
Aart Bikc071a012016-12-01 10:22:31 -08001434 return graph_->GetLongConstant(1L << value);
1435 }
1436 }
1437 return nullptr;
1438}
Aart Bikcc42be02016-10-20 16:14:16 -07001439
Vladimir Markode4d1952022-03-07 09:29:40 +00001440void HInductionVarAnalysis::AssignCycle(HPhi* phi, ArrayRef<HInstruction* const> scc) {
Aart Bikcc42be02016-10-20 16:14:16 -07001441 ArenaSet<HInstruction*>* set = &cycles_.Put(phi, ArenaSet<HInstruction*>(
Vladimir Markoca6fff82017-10-03 14:49:14 +01001442 graph_->GetAllocator()->Adapter(kArenaAllocInductionVarAnalysis)))->second;
Vladimir Markode4d1952022-03-07 09:29:40 +00001443 for (HInstruction* i : scc) {
Aart Bikcc42be02016-10-20 16:14:16 -07001444 set->insert(i);
1445 }
1446}
1447
1448ArenaSet<HInstruction*>* HInductionVarAnalysis::LookupCycle(HPhi* phi) {
1449 auto it = cycles_.find(phi);
1450 if (it != cycles_.end()) {
1451 return &it->second;
1452 }
1453 return nullptr;
1454}
1455
Vladimir Marko8d100ba2022-03-04 10:13:10 +00001456bool HInductionVarAnalysis::IsExact(const HBasicBlock* context,
1457 const HLoopInformation* loop,
1458 InductionInfo* info,
1459 /*out*/int64_t* value) {
1460 InductionVarRange range(this);
1461 return range.IsConstant(context, loop, info, InductionVarRange::kExact, value);
Aart Bik97412c922016-02-19 20:14:38 -08001462}
1463
Vladimir Marko8d100ba2022-03-04 10:13:10 +00001464bool HInductionVarAnalysis::IsAtMost(const HBasicBlock* context,
1465 const HLoopInformation* loop,
1466 InductionInfo* info,
1467 /*out*/int64_t* value) {
1468 InductionVarRange range(this);
1469 return range.IsConstant(context, loop, info, InductionVarRange::kAtMost, value);
Aart Bik97412c922016-02-19 20:14:38 -08001470}
1471
Vladimir Marko8d100ba2022-03-04 10:13:10 +00001472bool HInductionVarAnalysis::IsAtLeast(const HBasicBlock* context,
1473 const HLoopInformation* loop,
1474 InductionInfo* info,
1475 /*out*/int64_t* value) {
1476 InductionVarRange range(this);
1477 return range.IsConstant(context, loop, info, InductionVarRange::kAtLeast, value);
Aart Bik7d57d7f2015-12-09 14:39:48 -08001478}
1479
Aart Bike6bd0272016-12-16 13:57:52 -08001480bool HInductionVarAnalysis::IsNarrowingLinear(InductionInfo* info) {
1481 return info != nullptr &&
1482 info->induction_class == kLinear &&
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01001483 (info->type == DataType::Type::kUint8 ||
1484 info->type == DataType::Type::kInt8 ||
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001485 info->type == DataType::Type::kUint16 ||
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01001486 info->type == DataType::Type::kInt16 ||
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001487 (info->type == DataType::Type::kInt32 && (info->op_a->type == DataType::Type::kInt64 ||
1488 info->op_b->type == DataType::Type::kInt64)));
Aart Bike6bd0272016-12-16 13:57:52 -08001489}
1490
Aart Bik30efb4e2015-07-30 12:14:31 -07001491bool HInductionVarAnalysis::InductionEqual(InductionInfo* info1,
1492 InductionInfo* info2) {
1493 // Test structural equality only, without accounting for simplifications.
1494 if (info1 != nullptr && info2 != nullptr) {
1495 return
1496 info1->induction_class == info2->induction_class &&
1497 info1->operation == info2->operation &&
1498 info1->fetch == info2->fetch &&
Aart Bik78296912016-03-25 13:14:53 -07001499 info1->type == info2->type &&
Aart Bik30efb4e2015-07-30 12:14:31 -07001500 InductionEqual(info1->op_a, info2->op_a) &&
1501 InductionEqual(info1->op_b, info2->op_b);
1502 }
1503 // Otherwise only two nullptrs are considered equal.
1504 return info1 == info2;
1505}
1506
Aart Bikc071a012016-12-01 10:22:31 -08001507std::string HInductionVarAnalysis::FetchToString(HInstruction* fetch) {
1508 DCHECK(fetch != nullptr);
1509 if (fetch->IsIntConstant()) {
1510 return std::to_string(fetch->AsIntConstant()->GetValue());
1511 } else if (fetch->IsLongConstant()) {
1512 return std::to_string(fetch->AsLongConstant()->GetValue());
1513 }
1514 return std::to_string(fetch->GetId()) + ":" + fetch->DebugName();
1515}
1516
Aart Bik30efb4e2015-07-30 12:14:31 -07001517std::string HInductionVarAnalysis::InductionToString(InductionInfo* info) {
1518 if (info != nullptr) {
1519 if (info->induction_class == kInvariant) {
1520 std::string inv = "(";
1521 inv += InductionToString(info->op_a);
1522 switch (info->operation) {
Aart Bik22f05872015-10-27 15:56:28 -07001523 case kNop: inv += " @ "; break;
1524 case kAdd: inv += " + "; break;
Aart Bik30efb4e2015-07-30 12:14:31 -07001525 case kSub:
Aart Bik22f05872015-10-27 15:56:28 -07001526 case kNeg: inv += " - "; break;
1527 case kMul: inv += " * "; break;
1528 case kDiv: inv += " / "; break;
Aart Bikdf7822e2016-12-06 10:05:30 -08001529 case kRem: inv += " % "; break;
Aart Bik7dc96932016-10-12 10:01:05 -07001530 case kXor: inv += " ^ "; break;
Aart Bik22f05872015-10-27 15:56:28 -07001531 case kLT: inv += " < "; break;
1532 case kLE: inv += " <= "; break;
1533 case kGT: inv += " > "; break;
1534 case kGE: inv += " >= "; break;
Aart Bikc071a012016-12-01 10:22:31 -08001535 case kFetch: inv += FetchToString(info->fetch); break;
Aart Bik22f05872015-10-27 15:56:28 -07001536 case kTripCountInLoop: inv += " (TC-loop) "; break;
1537 case kTripCountInBody: inv += " (TC-body) "; break;
1538 case kTripCountInLoopUnsafe: inv += " (TC-loop-unsafe) "; break;
1539 case kTripCountInBodyUnsafe: inv += " (TC-body-unsafe) "; break;
Aart Bik30efb4e2015-07-30 12:14:31 -07001540 }
1541 inv += InductionToString(info->op_b);
Aart Bik0d345cf2016-03-16 10:49:38 -07001542 inv += ")";
1543 return inv;
Aart Bik30efb4e2015-07-30 12:14:31 -07001544 } else {
Aart Bik30efb4e2015-07-30 12:14:31 -07001545 if (info->induction_class == kLinear) {
Aart Bikdf7822e2016-12-06 10:05:30 -08001546 DCHECK(info->operation == kNop);
Aart Bik30efb4e2015-07-30 12:14:31 -07001547 return "(" + InductionToString(info->op_a) + " * i + " +
Aart Bik0d345cf2016-03-16 10:49:38 -07001548 InductionToString(info->op_b) + "):" +
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001549 DataType::PrettyDescriptor(info->type);
Aart Bikc071a012016-12-01 10:22:31 -08001550 } else if (info->induction_class == kPolynomial) {
Aart Bikdf7822e2016-12-06 10:05:30 -08001551 DCHECK(info->operation == kNop);
1552 return "poly(sum_lt(" + InductionToString(info->op_a) + ") + " +
Aart Bikc071a012016-12-01 10:22:31 -08001553 InductionToString(info->op_b) + "):" +
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001554 DataType::PrettyDescriptor(info->type);
Aart Bikc071a012016-12-01 10:22:31 -08001555 } else if (info->induction_class == kGeometric) {
Aart Bikdf7822e2016-12-06 10:05:30 -08001556 DCHECK(info->operation == kMul || info->operation == kDiv);
Aart Bikc071a012016-12-01 10:22:31 -08001557 DCHECK(info->fetch != nullptr);
Aart Bikdf7822e2016-12-06 10:05:30 -08001558 return "geo(" + InductionToString(info->op_a) + " * " +
1559 FetchToString(info->fetch) +
1560 (info->operation == kMul ? " ^ i + " : " ^ -i + ") +
1561 InductionToString(info->op_b) + "):" +
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001562 DataType::PrettyDescriptor(info->type);
Aart Bik30efb4e2015-07-30 12:14:31 -07001563 } else if (info->induction_class == kWrapAround) {
Aart Bikdf7822e2016-12-06 10:05:30 -08001564 DCHECK(info->operation == kNop);
Aart Bik30efb4e2015-07-30 12:14:31 -07001565 return "wrap(" + InductionToString(info->op_a) + ", " +
Aart Bik0d345cf2016-03-16 10:49:38 -07001566 InductionToString(info->op_b) + "):" +
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001567 DataType::PrettyDescriptor(info->type);
Aart Bik30efb4e2015-07-30 12:14:31 -07001568 } else if (info->induction_class == kPeriodic) {
Aart Bikdf7822e2016-12-06 10:05:30 -08001569 DCHECK(info->operation == kNop);
Aart Bik30efb4e2015-07-30 12:14:31 -07001570 return "periodic(" + InductionToString(info->op_a) + ", " +
Aart Bik0d345cf2016-03-16 10:49:38 -07001571 InductionToString(info->op_b) + "):" +
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001572 DataType::PrettyDescriptor(info->type);
Aart Bik30efb4e2015-07-30 12:14:31 -07001573 }
1574 }
1575 }
1576 return "";
1577}
1578
1579} // namespace art