blob: 09417722da88af51a30cd2e8cb2590ef0e96b895 [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"
24#include "base/scoped_arena_containers.h"
Aart Bik30efb4e2015-07-30 12:14:31 -070025#include "nodes.h"
26#include "optimization.h"
27
Vladimir Marko0a516052019-10-14 13:00:44 +000028namespace art {
Aart Bik30efb4e2015-07-30 12:14:31 -070029
30/**
Aart Bike609b7c2015-08-27 13:46:58 -070031 * Induction variable analysis. This class does not have a direct public API.
32 * Instead, the results of induction variable analysis can be queried through
33 * friend classes, such as InductionVarRange.
Aart Bik30efb4e2015-07-30 12:14:31 -070034 *
Aart Bike609b7c2015-08-27 13:46:58 -070035 * The analysis implementation is based on the paper by M. Gerlek et al.
Aart Bik30efb4e2015-07-30 12:14:31 -070036 * "Beyond Induction Variables: Detecting and Classifying Sequences Using a Demand-Driven SSA Form"
37 * (ACM Transactions on Programming Languages and Systems, Volume 17 Issue 1, Jan. 1995).
38 */
39class HInductionVarAnalysis : public HOptimization {
40 public:
Aart Bik2ca10eb2017-11-15 15:17:53 -080041 explicit HInductionVarAnalysis(HGraph* graph, const char* name = kInductionPassName);
Aart Bik30efb4e2015-07-30 12:14:31 -070042
Roland Levillainbbc6e7e2018-08-24 16:58:47 +010043 bool Run() override;
Aart Bik30efb4e2015-07-30 12:14:31 -070044
Aart Bik30efb4e2015-07-30 12:14:31 -070045 static constexpr const char* kInductionPassName = "induction_var_analysis";
46
Wojciech Staszkiewicz5319d3c2016-08-01 17:48:59 -070047 private:
Vladimir Markode4d1952022-03-07 09:29:40 +000048 struct NodeInfo;
49 struct StackEntry;
Aart Bik30efb4e2015-07-30 12:14:31 -070050
51 enum InductionClass {
Aart Bik30efb4e2015-07-30 12:14:31 -070052 kInvariant,
53 kLinear,
Aart Bikc071a012016-12-01 10:22:31 -080054 kPolynomial,
55 kGeometric,
Aart Bik30efb4e2015-07-30 12:14:31 -070056 kWrapAround,
Aart Bike609b7c2015-08-27 13:46:58 -070057 kPeriodic
Aart Bik30efb4e2015-07-30 12:14:31 -070058 };
59
60 enum InductionOp {
Aart Bikc071a012016-12-01 10:22:31 -080061 // Operations.
Aart Bik9401f532015-09-28 16:25:56 -070062 kNop,
Aart Bik30efb4e2015-07-30 12:14:31 -070063 kAdd,
64 kSub,
65 kNeg,
66 kMul,
67 kDiv,
Aart Bikdf7822e2016-12-06 10:05:30 -080068 kRem,
Aart Bik7dc96932016-10-12 10:01:05 -070069 kXor,
Aart Bik9401f532015-09-28 16:25:56 -070070 kFetch,
Aart Bik22f05872015-10-27 15:56:28 -070071 // Trip-counts.
72 kTripCountInLoop, // valid in full loop; loop is finite
73 kTripCountInBody, // valid in body only; loop is finite
74 kTripCountInLoopUnsafe, // valid in full loop; loop may be infinite
75 kTripCountInBodyUnsafe, // valid in body only; loop may be infinite
76 // Comparisons for trip-count tests.
77 kLT,
78 kLE,
79 kGT,
80 kGE
Aart Bik30efb4e2015-07-30 12:14:31 -070081 };
82
83 /**
84 * Defines a detected induction as:
85 * (1) invariant:
Aart Bikc071a012016-12-01 10:22:31 -080086 * op: a + b, a - b, -b, a * b, a / b, a % b, a ^ b, fetch
Aart Bik30efb4e2015-07-30 12:14:31 -070087 * (2) linear:
88 * nop: a * i + b
Aart Bikdf7822e2016-12-06 10:05:30 -080089 * (3) polynomial:
90 * nop: sum_lt(a) + b, for linear a
Aart Bikc071a012016-12-01 10:22:31 -080091 * (4) geometric:
Aart Bikdf7822e2016-12-06 10:05:30 -080092 * op: a * fetch^i + b, a * fetch^-i + b
Aart Bikc071a012016-12-01 10:22:31 -080093 * (5) wrap-around
Aart Bik30efb4e2015-07-30 12:14:31 -070094 * nop: a, then defined by b
Aart Bikc071a012016-12-01 10:22:31 -080095 * (6) periodic
Aart Bik30efb4e2015-07-30 12:14:31 -070096 * nop: a, then defined by b (repeated when exhausted)
Aart Bikc071a012016-12-01 10:22:31 -080097 * (7) trip-count:
Aart Bik22f05872015-10-27 15:56:28 -070098 * tc: defined by a, taken-test in b
Aart Bik30efb4e2015-07-30 12:14:31 -070099 */
Vladimir Marko5233f932015-09-29 19:01:15 +0100100 struct InductionInfo : public ArenaObject<kArenaAllocInductionVarAnalysis> {
Aart Bik30efb4e2015-07-30 12:14:31 -0700101 InductionInfo(InductionClass ic,
102 InductionOp op,
103 InductionInfo* a,
104 InductionInfo* b,
Aart Bik0d345cf2016-03-16 10:49:38 -0700105 HInstruction* f,
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100106 DataType::Type t)
Aart Bik30efb4e2015-07-30 12:14:31 -0700107 : induction_class(ic),
108 operation(op),
109 op_a(a),
110 op_b(b),
Aart Bik0d345cf2016-03-16 10:49:38 -0700111 fetch(f),
112 type(t) {}
Aart Bik30efb4e2015-07-30 12:14:31 -0700113 InductionClass induction_class;
114 InductionOp operation;
115 InductionInfo* op_a;
116 InductionInfo* op_b;
117 HInstruction* fetch;
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100118 DataType::Type type; // precision of operation
Aart Bik30efb4e2015-07-30 12:14:31 -0700119 };
120
Aart Bik30efb4e2015-07-30 12:14:31 -0700121
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000122 InductionInfo* CreateInvariantOp(const HBasicBlock* context,
123 const HLoopInformation* loop,
124 InductionOp op,
125 InductionInfo* a,
126 InductionInfo* b) {
Aart Bike609b7c2015-08-27 13:46:58 -0700127 DCHECK(((op != kNeg && a != nullptr) || (op == kNeg && a == nullptr)) && b != nullptr);
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000128 return CreateSimplifiedInvariant(context, loop, op, a, b);
Aart Bike609b7c2015-08-27 13:46:58 -0700129 }
130
Aart Bik471a2032015-09-04 18:22:11 -0700131 InductionInfo* CreateInvariantFetch(HInstruction* f) {
Aart Bike609b7c2015-08-27 13:46:58 -0700132 DCHECK(f != nullptr);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100133 return new (graph_->GetAllocator())
Aart Bik0d345cf2016-03-16 10:49:38 -0700134 InductionInfo(kInvariant, kFetch, nullptr, nullptr, f, f->GetType());
Aart Bike609b7c2015-08-27 13:46:58 -0700135 }
136
Aart Bik0d345cf2016-03-16 10:49:38 -0700137 InductionInfo* CreateTripCount(InductionOp op,
138 InductionInfo* a,
139 InductionInfo* b,
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100140 DataType::Type type) {
Aart Bik52be7e72016-06-23 11:20:41 -0700141 DCHECK(a != nullptr && b != nullptr);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100142 return new (graph_->GetAllocator()) InductionInfo(kInvariant, op, a, b, nullptr, type);
Aart Bik9401f532015-09-28 16:25:56 -0700143 }
144
Aart Bik0d345cf2016-03-16 10:49:38 -0700145 InductionInfo* CreateInduction(InductionClass ic,
Aart Bikc071a012016-12-01 10:22:31 -0800146 InductionOp op,
Aart Bik0d345cf2016-03-16 10:49:38 -0700147 InductionInfo* a,
148 InductionInfo* b,
Aart Bikc071a012016-12-01 10:22:31 -0800149 HInstruction* f,
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100150 DataType::Type type) {
Aart Bike609b7c2015-08-27 13:46:58 -0700151 DCHECK(a != nullptr && b != nullptr);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100152 return new (graph_->GetAllocator()) InductionInfo(ic, op, a, b, f, type);
Aart Bik30efb4e2015-07-30 12:14:31 -0700153 }
154
155 // Methods for analysis.
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000156 void VisitLoop(const HLoopInformation* loop);
157 size_t TryVisitNodes(const HLoopInformation* loop,
Vladimir Markode4d1952022-03-07 09:29:40 +0000158 HInstruction* start_instruction,
159 size_t global_depth,
160 /*inout*/ ScopedArenaSafeMap<HInstruction*, NodeInfo>* visited_instructions);
161 void ExtractScc(ArrayRef<const StackEntry> stack_tail, ScopedArenaVector<HInstruction*>* scc);
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000162 void ClassifyTrivial(const HLoopInformation* loop, HInstruction* instruction);
163 void ClassifyNonTrivial(const HLoopInformation* loop, ArrayRef<const StackEntry> stack_tail);
Vladimir Markode4d1952022-03-07 09:29:40 +0000164 InductionInfo* RotatePeriodicInduction(InductionInfo* induction,
165 InductionInfo* last,
166 DataType::Type type);
Aart Bik30efb4e2015-07-30 12:14:31 -0700167
168 // Transfer operations.
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000169 InductionInfo* TransferPhi(const HLoopInformation* loop,
Aart Bikd0a022d2016-12-13 11:22:31 -0800170 HInstruction* phi,
171 size_t input_index,
172 size_t adjust_input_size);
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000173 InductionInfo* TransferAddSub(const HBasicBlock* context,
174 const HLoopInformation* loop,
175 InductionInfo* a,
Vladimir Markode4d1952022-03-07 09:29:40 +0000176 InductionInfo* b,
177 InductionOp op,
178 DataType::Type type);
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000179 InductionInfo* TransferNeg(const HBasicBlock* context,
180 const HLoopInformation* loop,
181 InductionInfo* a,
182 DataType::Type type);
183 InductionInfo* TransferMul(const HBasicBlock* context,
184 const HLoopInformation* loop,
185 InductionInfo* a,
186 InductionInfo* b,
187 DataType::Type type);
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100188 InductionInfo* TransferConversion(InductionInfo* a, DataType::Type from, DataType::Type to);
Aart Bike609b7c2015-08-27 13:46:58 -0700189
190 // Solvers.
Vladimir Markode4d1952022-03-07 09:29:40 +0000191 InductionInfo* SolvePhi(HInstruction* phi,
192 size_t input_index,
193 size_t adjust_input_size,
194 const ScopedArenaSafeMap<HInstruction*, InductionInfo*>& cycle);
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000195 InductionInfo* SolvePhiAllInputs(const HLoopInformation* loop,
Aart Bikf475bee2015-09-16 12:50:25 -0700196 HInstruction* entry_phi,
Vladimir Markode4d1952022-03-07 09:29:40 +0000197 HInstruction* phi,
198 const ScopedArenaSafeMap<HInstruction*, InductionInfo*>& cycle,
199 DataType::Type type);
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000200 InductionInfo* SolveAddSub(const HLoopInformation* loop,
Aart Bikf475bee2015-09-16 12:50:25 -0700201 HInstruction* entry_phi,
Aart Bike609b7c2015-08-27 13:46:58 -0700202 HInstruction* instruction,
203 HInstruction* x,
204 HInstruction* y,
205 InductionOp op,
Vladimir Markode4d1952022-03-07 09:29:40 +0000206 const ScopedArenaSafeMap<HInstruction*, InductionInfo*>& cycle,
207 DataType::Type type);
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000208 InductionInfo* SolveOp(const HLoopInformation* loop,
Aart Bikdf7822e2016-12-06 10:05:30 -0800209 HInstruction* entry_phi,
210 HInstruction* instruction,
211 HInstruction* x,
212 HInstruction* y,
Vladimir Markode4d1952022-03-07 09:29:40 +0000213 InductionOp op,
214 DataType::Type type);
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000215 InductionInfo* SolveTest(const HLoopInformation* loop,
Aart Bik639cc8c2016-10-18 13:03:31 -0700216 HInstruction* entry_phi,
217 HInstruction* instruction,
Vladimir Markode4d1952022-03-07 09:29:40 +0000218 int64_t opposite_value,
219 DataType::Type type);
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000220 InductionInfo* SolveConversion(const HLoopInformation* loop,
Aart Bike6bd0272016-12-16 13:57:52 -0800221 HInstruction* entry_phi,
Vladimir Markode4d1952022-03-07 09:29:40 +0000222 HTypeConversion* conversion,
223 const ScopedArenaSafeMap<HInstruction*, InductionInfo*>& cycle,
224 /*inout*/ DataType::Type* type);
Aart Bik30efb4e2015-07-30 12:14:31 -0700225
Aart Bikceb06932017-11-13 10:31:17 -0800226 //
227 // Loop trip count analysis methods.
228 //
229
Aart Bikd14c5952015-09-08 15:25:15 -0700230 // Trip count information.
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000231 void VisitControl(const HLoopInformation* loop);
232 void VisitCondition(const HBasicBlock* context,
233 const HLoopInformation* loop,
Aart Bikceb06932017-11-13 10:31:17 -0800234 HBasicBlock* body,
Aart Bikd14c5952015-09-08 15:25:15 -0700235 InductionInfo* a,
236 InductionInfo* b,
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100237 DataType::Type type,
Aart Bikd14c5952015-09-08 15:25:15 -0700238 IfCondition cmp);
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000239 void VisitTripCount(const HBasicBlock* context,
240 const HLoopInformation* loop,
Aart Bik9401f532015-09-28 16:25:56 -0700241 InductionInfo* lower_expr,
242 InductionInfo* upper_expr,
Aart Bikd14c5952015-09-08 15:25:15 -0700243 InductionInfo* stride,
Aart Bik9401f532015-09-28 16:25:56 -0700244 int64_t stride_value,
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100245 DataType::Type type,
Aart Bikf475bee2015-09-16 12:50:25 -0700246 IfCondition cmp);
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000247 bool IsTaken(const HBasicBlock* context,
248 const HLoopInformation* loop,
249 InductionInfo* lower_expr,
250 InductionInfo* upper_expr,
251 IfCondition cmp);
252 bool IsFinite(const HBasicBlock* context,
253 const HLoopInformation* loop,
254 InductionInfo* upper_expr,
Aart Bik9401f532015-09-28 16:25:56 -0700255 int64_t stride_value,
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100256 DataType::Type type,
Aart Bik9401f532015-09-28 16:25:56 -0700257 IfCondition cmp);
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000258 bool FitsNarrowerControl(const HBasicBlock* context,
259 const HLoopInformation* loop,
260 InductionInfo* lower_expr,
Aart Bik0d345cf2016-03-16 10:49:38 -0700261 InductionInfo* upper_expr,
262 int64_t stride_value,
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100263 DataType::Type type,
Aart Bik0d345cf2016-03-16 10:49:38 -0700264 IfCondition cmp);
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000265 bool RewriteBreakLoop(const HBasicBlock* context,
266 const HLoopInformation* loop,
Aart Bikceb06932017-11-13 10:31:17 -0800267 HBasicBlock* body,
268 int64_t stride_value,
269 DataType::Type type);
270
271 //
272 // Helper methods.
273 //
Aart Bikd14c5952015-09-08 15:25:15 -0700274
Aart Bik30efb4e2015-07-30 12:14:31 -0700275 // Assign and lookup.
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000276 void AssignInfo(const HLoopInformation* loop, HInstruction* instruction, InductionInfo* info);
277 InductionInfo* LookupInfo(const HLoopInformation* loop, HInstruction* instruction);
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100278 InductionInfo* CreateConstant(int64_t value, DataType::Type type);
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000279 InductionInfo* CreateSimplifiedInvariant(const HBasicBlock* context,
280 const HLoopInformation* loop,
281 InductionOp op,
282 InductionInfo* a,
283 InductionInfo* b);
284 HInstruction* GetShiftConstant(const HLoopInformation* loop,
Aart Bikd0a022d2016-12-13 11:22:31 -0800285 HInstruction* instruction,
286 InductionInfo* initial);
Vladimir Markode4d1952022-03-07 09:29:40 +0000287 void AssignCycle(HPhi* phi, ArrayRef<HInstruction* const> scc);
Aart Bikcc42be02016-10-20 16:14:16 -0700288 ArenaSet<HInstruction*>* LookupCycle(HPhi* phi);
Aart Bik30efb4e2015-07-30 12:14:31 -0700289
Aart Bik7d57d7f2015-12-09 14:39:48 -0800290 // Constants.
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000291 bool IsExact(const HBasicBlock* context,
292 const HLoopInformation* loop,
293 InductionInfo* info,
294 /*out*/int64_t* value);
295 bool IsAtMost(const HBasicBlock* context,
296 const HLoopInformation* loop,
297 InductionInfo* info,
298 /*out*/int64_t* value);
299 bool IsAtLeast(const HBasicBlock* context,
300 const HLoopInformation* loop,
301 InductionInfo* info,
302 /*out*/int64_t* value);
Aart Bik7d57d7f2015-12-09 14:39:48 -0800303
Aart Bike609b7c2015-08-27 13:46:58 -0700304 // Helpers.
Aart Bike6bd0272016-12-16 13:57:52 -0800305 static bool IsNarrowingLinear(InductionInfo* info);
Aart Bike609b7c2015-08-27 13:46:58 -0700306 static bool InductionEqual(InductionInfo* info1, InductionInfo* info2);
Aart Bikc071a012016-12-01 10:22:31 -0800307 static std::string FetchToString(HInstruction* fetch);
Aart Bike609b7c2015-08-27 13:46:58 -0700308 static std::string InductionToString(InductionInfo* info);
Aart Bik30efb4e2015-07-30 12:14:31 -0700309
Aart Bike609b7c2015-08-27 13:46:58 -0700310 /**
311 * Maintains the results of the analysis as a mapping from loops to a mapping from instructions
312 * to the induction information for that instruction in that loop.
313 */
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000314 ArenaSafeMap<const HLoopInformation*, ArenaSafeMap<HInstruction*, InductionInfo*>> induction_;
Aart Bik30efb4e2015-07-30 12:14:31 -0700315
Aart Bikcc42be02016-10-20 16:14:16 -0700316 /**
317 * Preserves induction cycle information for each loop-phi.
318 */
319 ArenaSafeMap<HPhi*, ArenaSet<HInstruction*>> cycles_;
320
Aart Bike609b7c2015-08-27 13:46:58 -0700321 friend class InductionVarAnalysisTest;
Aart Bikd14c5952015-09-08 15:25:15 -0700322 friend class InductionVarRange;
323 friend class InductionVarRangeTest;
Aart Bik30efb4e2015-07-30 12:14:31 -0700324
325 DISALLOW_COPY_AND_ASSIGN(HInductionVarAnalysis);
326};
327
328} // namespace art
329
330#endif // ART_COMPILER_OPTIMIZING_INDUCTION_VAR_ANALYSIS_H_