blob: 050950089aa23da7fc30eca5bc0095de374ddffe [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#ifndef ART_COMPILER_OPTIMIZING_INDUCTION_VAR_ANALYSIS_H_
18#define ART_COMPILER_OPTIMIZING_INDUCTION_VAR_ANALYSIS_H_
19
20#include <string>
21
Vladimir Markode4d1952022-03-07 09:29:40 +000022#include "base/arena_containers.h"
23#include "base/array_ref.h"
Vladimír Marko434d9682022-11-04 14:04:17 +000024#include "base/macros.h"
Vladimir Markode4d1952022-03-07 09:29:40 +000025#include "base/scoped_arena_containers.h"
Aart Bik30efb4e2015-07-30 12:14:31 -070026#include "nodes.h"
27#include "optimization.h"
28
Vladimír Marko434d9682022-11-04 14:04:17 +000029namespace art HIDDEN {
Aart Bik30efb4e2015-07-30 12:14:31 -070030
31/**
Aart Bike609b7c2015-08-27 13:46:58 -070032 * Induction variable analysis. This class does not have a direct public API.
33 * Instead, the results of induction variable analysis can be queried through
34 * friend classes, such as InductionVarRange.
Aart Bik30efb4e2015-07-30 12:14:31 -070035 *
Aart Bike609b7c2015-08-27 13:46:58 -070036 * The analysis implementation is based on the paper by M. Gerlek et al.
Aart Bik30efb4e2015-07-30 12:14:31 -070037 * "Beyond Induction Variables: Detecting and Classifying Sequences Using a Demand-Driven SSA Form"
38 * (ACM Transactions on Programming Languages and Systems, Volume 17 Issue 1, Jan. 1995).
39 */
40class HInductionVarAnalysis : public HOptimization {
41 public:
Santiago Aboy Solanes3633fe42023-01-12 16:10:05 +000042 explicit HInductionVarAnalysis(HGraph* graph,
43 OptimizingCompilerStats* stats = nullptr,
44 const char* name = kInductionPassName);
Aart Bik30efb4e2015-07-30 12:14:31 -070045
Roland Levillainbbc6e7e2018-08-24 16:58:47 +010046 bool Run() override;
Aart Bik30efb4e2015-07-30 12:14:31 -070047
Aart Bik30efb4e2015-07-30 12:14:31 -070048 static constexpr const char* kInductionPassName = "induction_var_analysis";
49
Wojciech Staszkiewicz5319d3c2016-08-01 17:48:59 -070050 private:
Vladimir Markode4d1952022-03-07 09:29:40 +000051 struct NodeInfo;
52 struct StackEntry;
Aart Bik30efb4e2015-07-30 12:14:31 -070053
54 enum InductionClass {
Aart Bik30efb4e2015-07-30 12:14:31 -070055 kInvariant,
56 kLinear,
Aart Bikc071a012016-12-01 10:22:31 -080057 kPolynomial,
58 kGeometric,
Aart Bik30efb4e2015-07-30 12:14:31 -070059 kWrapAround,
Aart Bike609b7c2015-08-27 13:46:58 -070060 kPeriodic
Aart Bik30efb4e2015-07-30 12:14:31 -070061 };
62
63 enum InductionOp {
Aart Bikc071a012016-12-01 10:22:31 -080064 // Operations.
Aart Bik9401f532015-09-28 16:25:56 -070065 kNop,
Aart Bik30efb4e2015-07-30 12:14:31 -070066 kAdd,
67 kSub,
68 kNeg,
69 kMul,
70 kDiv,
Aart Bikdf7822e2016-12-06 10:05:30 -080071 kRem,
Aart Bik7dc96932016-10-12 10:01:05 -070072 kXor,
Aart Bik9401f532015-09-28 16:25:56 -070073 kFetch,
Aart Bik22f05872015-10-27 15:56:28 -070074 // Trip-counts.
75 kTripCountInLoop, // valid in full loop; loop is finite
76 kTripCountInBody, // valid in body only; loop is finite
77 kTripCountInLoopUnsafe, // valid in full loop; loop may be infinite
78 kTripCountInBodyUnsafe, // valid in body only; loop may be infinite
79 // Comparisons for trip-count tests.
80 kLT,
81 kLE,
82 kGT,
83 kGE
Aart Bik30efb4e2015-07-30 12:14:31 -070084 };
85
86 /**
87 * Defines a detected induction as:
88 * (1) invariant:
Aart Bikc071a012016-12-01 10:22:31 -080089 * op: a + b, a - b, -b, a * b, a / b, a % b, a ^ b, fetch
Aart Bik30efb4e2015-07-30 12:14:31 -070090 * (2) linear:
91 * nop: a * i + b
Aart Bikdf7822e2016-12-06 10:05:30 -080092 * (3) polynomial:
93 * nop: sum_lt(a) + b, for linear a
Aart Bikc071a012016-12-01 10:22:31 -080094 * (4) geometric:
Aart Bikdf7822e2016-12-06 10:05:30 -080095 * op: a * fetch^i + b, a * fetch^-i + b
Aart Bikc071a012016-12-01 10:22:31 -080096 * (5) wrap-around
Aart Bik30efb4e2015-07-30 12:14:31 -070097 * nop: a, then defined by b
Aart Bikc071a012016-12-01 10:22:31 -080098 * (6) periodic
Aart Bik30efb4e2015-07-30 12:14:31 -070099 * nop: a, then defined by b (repeated when exhausted)
Aart Bikc071a012016-12-01 10:22:31 -0800100 * (7) trip-count:
Aart Bik22f05872015-10-27 15:56:28 -0700101 * tc: defined by a, taken-test in b
Aart Bik30efb4e2015-07-30 12:14:31 -0700102 */
Vladimir Marko5233f932015-09-29 19:01:15 +0100103 struct InductionInfo : public ArenaObject<kArenaAllocInductionVarAnalysis> {
Aart Bik30efb4e2015-07-30 12:14:31 -0700104 InductionInfo(InductionClass ic,
105 InductionOp op,
106 InductionInfo* a,
107 InductionInfo* b,
Aart Bik0d345cf2016-03-16 10:49:38 -0700108 HInstruction* f,
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100109 DataType::Type t)
Aart Bik30efb4e2015-07-30 12:14:31 -0700110 : induction_class(ic),
111 operation(op),
112 op_a(a),
113 op_b(b),
Aart Bik0d345cf2016-03-16 10:49:38 -0700114 fetch(f),
115 type(t) {}
Aart Bik30efb4e2015-07-30 12:14:31 -0700116 InductionClass induction_class;
117 InductionOp operation;
118 InductionInfo* op_a;
119 InductionInfo* op_b;
120 HInstruction* fetch;
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100121 DataType::Type type; // precision of operation
Aart Bik30efb4e2015-07-30 12:14:31 -0700122 };
123
Aart Bik30efb4e2015-07-30 12:14:31 -0700124
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000125 InductionInfo* CreateInvariantOp(const HBasicBlock* context,
126 const HLoopInformation* loop,
127 InductionOp op,
128 InductionInfo* a,
129 InductionInfo* b) {
Aart Bike609b7c2015-08-27 13:46:58 -0700130 DCHECK(((op != kNeg && a != nullptr) || (op == kNeg && a == nullptr)) && b != nullptr);
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000131 return CreateSimplifiedInvariant(context, loop, op, a, b);
Aart Bike609b7c2015-08-27 13:46:58 -0700132 }
133
Aart Bik471a2032015-09-04 18:22:11 -0700134 InductionInfo* CreateInvariantFetch(HInstruction* f) {
Aart Bike609b7c2015-08-27 13:46:58 -0700135 DCHECK(f != nullptr);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100136 return new (graph_->GetAllocator())
Aart Bik0d345cf2016-03-16 10:49:38 -0700137 InductionInfo(kInvariant, kFetch, nullptr, nullptr, f, f->GetType());
Aart Bike609b7c2015-08-27 13:46:58 -0700138 }
139
Aart Bik0d345cf2016-03-16 10:49:38 -0700140 InductionInfo* CreateTripCount(InductionOp op,
141 InductionInfo* a,
142 InductionInfo* b,
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100143 DataType::Type type) {
Aart Bik52be7e72016-06-23 11:20:41 -0700144 DCHECK(a != nullptr && b != nullptr);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100145 return new (graph_->GetAllocator()) InductionInfo(kInvariant, op, a, b, nullptr, type);
Aart Bik9401f532015-09-28 16:25:56 -0700146 }
147
Aart Bik0d345cf2016-03-16 10:49:38 -0700148 InductionInfo* CreateInduction(InductionClass ic,
Aart Bikc071a012016-12-01 10:22:31 -0800149 InductionOp op,
Aart Bik0d345cf2016-03-16 10:49:38 -0700150 InductionInfo* a,
151 InductionInfo* b,
Aart Bikc071a012016-12-01 10:22:31 -0800152 HInstruction* f,
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100153 DataType::Type type) {
Aart Bike609b7c2015-08-27 13:46:58 -0700154 DCHECK(a != nullptr && b != nullptr);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100155 return new (graph_->GetAllocator()) InductionInfo(ic, op, a, b, f, type);
Aart Bik30efb4e2015-07-30 12:14:31 -0700156 }
157
158 // Methods for analysis.
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000159 void VisitLoop(const HLoopInformation* loop);
160 size_t TryVisitNodes(const HLoopInformation* loop,
Vladimir Markode4d1952022-03-07 09:29:40 +0000161 HInstruction* start_instruction,
162 size_t global_depth,
163 /*inout*/ ScopedArenaSafeMap<HInstruction*, NodeInfo>* visited_instructions);
164 void ExtractScc(ArrayRef<const StackEntry> stack_tail, ScopedArenaVector<HInstruction*>* scc);
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000165 void ClassifyTrivial(const HLoopInformation* loop, HInstruction* instruction);
166 void ClassifyNonTrivial(const HLoopInformation* loop, ArrayRef<const StackEntry> stack_tail);
Vladimir Markode4d1952022-03-07 09:29:40 +0000167 InductionInfo* RotatePeriodicInduction(InductionInfo* induction,
168 InductionInfo* last,
169 DataType::Type type);
Aart Bik30efb4e2015-07-30 12:14:31 -0700170
171 // Transfer operations.
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000172 InductionInfo* TransferPhi(const HLoopInformation* loop,
Aart Bikd0a022d2016-12-13 11:22:31 -0800173 HInstruction* phi,
174 size_t input_index,
175 size_t adjust_input_size);
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000176 InductionInfo* TransferAddSub(const HBasicBlock* context,
177 const HLoopInformation* loop,
178 InductionInfo* a,
Vladimir Markode4d1952022-03-07 09:29:40 +0000179 InductionInfo* b,
180 InductionOp op,
181 DataType::Type type);
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000182 InductionInfo* TransferNeg(const HBasicBlock* context,
183 const HLoopInformation* loop,
184 InductionInfo* a,
185 DataType::Type type);
186 InductionInfo* TransferMul(const HBasicBlock* context,
187 const HLoopInformation* loop,
188 InductionInfo* a,
189 InductionInfo* b,
190 DataType::Type type);
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100191 InductionInfo* TransferConversion(InductionInfo* a, DataType::Type from, DataType::Type to);
Aart Bike609b7c2015-08-27 13:46:58 -0700192
193 // Solvers.
Vladimir Markode4d1952022-03-07 09:29:40 +0000194 InductionInfo* SolvePhi(HInstruction* phi,
195 size_t input_index,
196 size_t adjust_input_size,
197 const ScopedArenaSafeMap<HInstruction*, InductionInfo*>& cycle);
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000198 InductionInfo* SolvePhiAllInputs(const HLoopInformation* loop,
Aart Bikf475bee2015-09-16 12:50:25 -0700199 HInstruction* entry_phi,
Vladimir Markode4d1952022-03-07 09:29:40 +0000200 HInstruction* phi,
201 const ScopedArenaSafeMap<HInstruction*, InductionInfo*>& cycle,
202 DataType::Type type);
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000203 InductionInfo* SolveAddSub(const HLoopInformation* loop,
Aart Bikf475bee2015-09-16 12:50:25 -0700204 HInstruction* entry_phi,
Aart Bike609b7c2015-08-27 13:46:58 -0700205 HInstruction* instruction,
206 HInstruction* x,
207 HInstruction* y,
208 InductionOp op,
Vladimir Markode4d1952022-03-07 09:29:40 +0000209 const ScopedArenaSafeMap<HInstruction*, InductionInfo*>& cycle,
210 DataType::Type type);
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000211 InductionInfo* SolveOp(const HLoopInformation* loop,
Aart Bikdf7822e2016-12-06 10:05:30 -0800212 HInstruction* entry_phi,
213 HInstruction* instruction,
214 HInstruction* x,
215 HInstruction* y,
Vladimir Markode4d1952022-03-07 09:29:40 +0000216 InductionOp op,
217 DataType::Type type);
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000218 InductionInfo* SolveTest(const HLoopInformation* loop,
Aart Bik639cc8c2016-10-18 13:03:31 -0700219 HInstruction* entry_phi,
220 HInstruction* instruction,
Vladimir Markode4d1952022-03-07 09:29:40 +0000221 int64_t opposite_value,
222 DataType::Type type);
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000223 InductionInfo* SolveConversion(const HLoopInformation* loop,
Aart Bike6bd0272016-12-16 13:57:52 -0800224 HInstruction* entry_phi,
Vladimir Markode4d1952022-03-07 09:29:40 +0000225 HTypeConversion* conversion,
226 const ScopedArenaSafeMap<HInstruction*, InductionInfo*>& cycle,
227 /*inout*/ DataType::Type* type);
Aart Bik30efb4e2015-07-30 12:14:31 -0700228
Aart Bikceb06932017-11-13 10:31:17 -0800229 //
230 // Loop trip count analysis methods.
231 //
232
Aart Bikd14c5952015-09-08 15:25:15 -0700233 // Trip count information.
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000234 void VisitControl(const HLoopInformation* loop);
235 void VisitCondition(const HBasicBlock* context,
236 const HLoopInformation* loop,
Aart Bikceb06932017-11-13 10:31:17 -0800237 HBasicBlock* body,
Aart Bikd14c5952015-09-08 15:25:15 -0700238 InductionInfo* a,
239 InductionInfo* b,
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100240 DataType::Type type,
Aart Bikd14c5952015-09-08 15:25:15 -0700241 IfCondition cmp);
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000242 void VisitTripCount(const HBasicBlock* context,
243 const HLoopInformation* loop,
Aart Bik9401f532015-09-28 16:25:56 -0700244 InductionInfo* lower_expr,
245 InductionInfo* upper_expr,
Aart Bikd14c5952015-09-08 15:25:15 -0700246 InductionInfo* stride,
Aart Bik9401f532015-09-28 16:25:56 -0700247 int64_t stride_value,
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100248 DataType::Type type,
Aart Bikf475bee2015-09-16 12:50:25 -0700249 IfCondition cmp);
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000250 bool IsTaken(const HBasicBlock* context,
251 const HLoopInformation* loop,
252 InductionInfo* lower_expr,
253 InductionInfo* upper_expr,
254 IfCondition cmp);
255 bool IsFinite(const HBasicBlock* context,
256 const HLoopInformation* loop,
257 InductionInfo* upper_expr,
Aart Bik9401f532015-09-28 16:25:56 -0700258 int64_t stride_value,
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100259 DataType::Type type,
Aart Bik9401f532015-09-28 16:25:56 -0700260 IfCondition cmp);
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000261 bool FitsNarrowerControl(const HBasicBlock* context,
262 const HLoopInformation* loop,
263 InductionInfo* lower_expr,
Aart Bik0d345cf2016-03-16 10:49:38 -0700264 InductionInfo* upper_expr,
265 int64_t stride_value,
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100266 DataType::Type type,
Aart Bik0d345cf2016-03-16 10:49:38 -0700267 IfCondition cmp);
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000268 bool RewriteBreakLoop(const HBasicBlock* context,
269 const HLoopInformation* loop,
Aart Bikceb06932017-11-13 10:31:17 -0800270 HBasicBlock* body,
271 int64_t stride_value,
272 DataType::Type type);
273
274 //
275 // Helper methods.
276 //
Aart Bikd14c5952015-09-08 15:25:15 -0700277
Aart Bik30efb4e2015-07-30 12:14:31 -0700278 // Assign and lookup.
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000279 void AssignInfo(const HLoopInformation* loop, HInstruction* instruction, InductionInfo* info);
280 InductionInfo* LookupInfo(const HLoopInformation* loop, HInstruction* instruction);
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100281 InductionInfo* CreateConstant(int64_t value, DataType::Type type);
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000282 InductionInfo* CreateSimplifiedInvariant(const HBasicBlock* context,
283 const HLoopInformation* loop,
284 InductionOp op,
285 InductionInfo* a,
286 InductionInfo* b);
287 HInstruction* GetShiftConstant(const HLoopInformation* loop,
Aart Bikd0a022d2016-12-13 11:22:31 -0800288 HInstruction* instruction,
289 InductionInfo* initial);
Vladimir Markode4d1952022-03-07 09:29:40 +0000290 void AssignCycle(HPhi* phi, ArrayRef<HInstruction* const> scc);
Aart Bikcc42be02016-10-20 16:14:16 -0700291 ArenaSet<HInstruction*>* LookupCycle(HPhi* phi);
Aart Bik30efb4e2015-07-30 12:14:31 -0700292
Aart Bik7d57d7f2015-12-09 14:39:48 -0800293 // Constants.
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000294 bool IsExact(const HBasicBlock* context,
295 const HLoopInformation* loop,
296 InductionInfo* info,
297 /*out*/int64_t* value);
298 bool IsAtMost(const HBasicBlock* context,
299 const HLoopInformation* loop,
300 InductionInfo* info,
301 /*out*/int64_t* value);
302 bool IsAtLeast(const HBasicBlock* context,
303 const HLoopInformation* loop,
304 InductionInfo* info,
305 /*out*/int64_t* value);
Aart Bik7d57d7f2015-12-09 14:39:48 -0800306
Aart Bike609b7c2015-08-27 13:46:58 -0700307 // Helpers.
Aart Bike6bd0272016-12-16 13:57:52 -0800308 static bool IsNarrowingLinear(InductionInfo* info);
Aart Bike609b7c2015-08-27 13:46:58 -0700309 static bool InductionEqual(InductionInfo* info1, InductionInfo* info2);
Aart Bikc071a012016-12-01 10:22:31 -0800310 static std::string FetchToString(HInstruction* fetch);
Aart Bike609b7c2015-08-27 13:46:58 -0700311 static std::string InductionToString(InductionInfo* info);
Aart Bik30efb4e2015-07-30 12:14:31 -0700312
Santiago Aboy Solanes3633fe42023-01-12 16:10:05 +0000313 // Returns true if we have a pathological case we don't want to analyze.
314 bool IsPathologicalCase();
315 // Starting with initial_phi, it calculates how many loop header phis in a row we have. To do
316 // this, we count the loop header phi which are used as an input of other loop header phis. It
317 // uses `cached_values` to avoid recomputing results.
318 void CalculateLoopHeaderPhisInARow(HPhi* initial_phi,
319 ScopedArenaSafeMap<HPhi*, int>& cached_values,
320 ScopedArenaAllocator& allocator);
321
Aart Bike609b7c2015-08-27 13:46:58 -0700322 /**
323 * Maintains the results of the analysis as a mapping from loops to a mapping from instructions
324 * to the induction information for that instruction in that loop.
325 */
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000326 ArenaSafeMap<const HLoopInformation*, ArenaSafeMap<HInstruction*, InductionInfo*>> induction_;
Aart Bik30efb4e2015-07-30 12:14:31 -0700327
Aart Bikcc42be02016-10-20 16:14:16 -0700328 /**
329 * Preserves induction cycle information for each loop-phi.
330 */
331 ArenaSafeMap<HPhi*, ArenaSet<HInstruction*>> cycles_;
332
Aart Bike609b7c2015-08-27 13:46:58 -0700333 friend class InductionVarAnalysisTest;
Aart Bikd14c5952015-09-08 15:25:15 -0700334 friend class InductionVarRange;
335 friend class InductionVarRangeTest;
Aart Bik30efb4e2015-07-30 12:14:31 -0700336
337 DISALLOW_COPY_AND_ASSIGN(HInductionVarAnalysis);
338};
339
340} // namespace art
341
342#endif // ART_COMPILER_OPTIMIZING_INDUCTION_VAR_ANALYSIS_H_