blob: 89fed2ec64b8859afab2467cb093aa8c1d96d556 [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
22#include "nodes.h"
23#include "optimization.h"
24
25namespace art {
26
27/**
Aart Bike609b7c2015-08-27 13:46:58 -070028 * Induction variable analysis. This class does not have a direct public API.
29 * Instead, the results of induction variable analysis can be queried through
30 * friend classes, such as InductionVarRange.
Aart Bik30efb4e2015-07-30 12:14:31 -070031 *
Aart Bike609b7c2015-08-27 13:46:58 -070032 * The analysis implementation is based on the paper by M. Gerlek et al.
Aart Bik30efb4e2015-07-30 12:14:31 -070033 * "Beyond Induction Variables: Detecting and Classifying Sequences Using a Demand-Driven SSA Form"
34 * (ACM Transactions on Programming Languages and Systems, Volume 17 Issue 1, Jan. 1995).
35 */
36class HInductionVarAnalysis : public HOptimization {
37 public:
Aart Bik2ca10eb2017-11-15 15:17:53 -080038 explicit HInductionVarAnalysis(HGraph* graph, const char* name = kInductionPassName);
Aart Bik30efb4e2015-07-30 12:14:31 -070039
Aart Bik24773202018-04-26 10:28:51 -070040 bool Run() OVERRIDE;
Aart Bik30efb4e2015-07-30 12:14:31 -070041
Aart Bik30efb4e2015-07-30 12:14:31 -070042 static constexpr const char* kInductionPassName = "induction_var_analysis";
43
Wojciech Staszkiewicz5319d3c2016-08-01 17:48:59 -070044 private:
Aart Bik30efb4e2015-07-30 12:14:31 -070045 struct NodeInfo {
46 explicit NodeInfo(uint32_t d) : depth(d), done(false) {}
47 uint32_t depth;
48 bool done;
49 };
50
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 Bike609b7c2015-08-27 13:46:58 -0700121 bool IsVisitedNode(HInstruction* instruction) const {
122 return map_.find(instruction) != map_.end();
Aart Bik30efb4e2015-07-30 12:14:31 -0700123 }
124
Aart Bik471a2032015-09-04 18:22:11 -0700125 InductionInfo* CreateInvariantOp(InductionOp op, InductionInfo* a, InductionInfo* b) {
Aart Bike609b7c2015-08-27 13:46:58 -0700126 DCHECK(((op != kNeg && a != nullptr) || (op == kNeg && a == nullptr)) && b != nullptr);
Aart Bik471a2032015-09-04 18:22:11 -0700127 return CreateSimplifiedInvariant(op, a, b);
Aart Bike609b7c2015-08-27 13:46:58 -0700128 }
129
Aart Bik471a2032015-09-04 18:22:11 -0700130 InductionInfo* CreateInvariantFetch(HInstruction* f) {
Aart Bike609b7c2015-08-27 13:46:58 -0700131 DCHECK(f != nullptr);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100132 return new (graph_->GetAllocator())
Aart Bik0d345cf2016-03-16 10:49:38 -0700133 InductionInfo(kInvariant, kFetch, nullptr, nullptr, f, f->GetType());
Aart Bike609b7c2015-08-27 13:46:58 -0700134 }
135
Aart Bik0d345cf2016-03-16 10:49:38 -0700136 InductionInfo* CreateTripCount(InductionOp op,
137 InductionInfo* a,
138 InductionInfo* b,
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100139 DataType::Type type) {
Aart Bik52be7e72016-06-23 11:20:41 -0700140 DCHECK(a != nullptr && b != nullptr);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100141 return new (graph_->GetAllocator()) InductionInfo(kInvariant, op, a, b, nullptr, type);
Aart Bik9401f532015-09-28 16:25:56 -0700142 }
143
Aart Bik0d345cf2016-03-16 10:49:38 -0700144 InductionInfo* CreateInduction(InductionClass ic,
Aart Bikc071a012016-12-01 10:22:31 -0800145 InductionOp op,
Aart Bik0d345cf2016-03-16 10:49:38 -0700146 InductionInfo* a,
147 InductionInfo* b,
Aart Bikc071a012016-12-01 10:22:31 -0800148 HInstruction* f,
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100149 DataType::Type type) {
Aart Bike609b7c2015-08-27 13:46:58 -0700150 DCHECK(a != nullptr && b != nullptr);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100151 return new (graph_->GetAllocator()) InductionInfo(ic, op, a, b, f, type);
Aart Bik30efb4e2015-07-30 12:14:31 -0700152 }
153
154 // Methods for analysis.
155 void VisitLoop(HLoopInformation* loop);
156 void VisitNode(HLoopInformation* loop, HInstruction* instruction);
157 uint32_t VisitDescendant(HLoopInformation* loop, HInstruction* instruction);
158 void ClassifyTrivial(HLoopInformation* loop, HInstruction* instruction);
159 void ClassifyNonTrivial(HLoopInformation* loop);
Aart Bikf475bee2015-09-16 12:50:25 -0700160 InductionInfo* RotatePeriodicInduction(InductionInfo* induction, InductionInfo* last);
Aart Bik30efb4e2015-07-30 12:14:31 -0700161
162 // Transfer operations.
Aart Bikd0a022d2016-12-13 11:22:31 -0800163 InductionInfo* TransferPhi(HLoopInformation* loop,
164 HInstruction* phi,
165 size_t input_index,
166 size_t adjust_input_size);
Aart Bik30efb4e2015-07-30 12:14:31 -0700167 InductionInfo* TransferAddSub(InductionInfo* a, InductionInfo* b, InductionOp op);
Aart Bik30efb4e2015-07-30 12:14:31 -0700168 InductionInfo* TransferNeg(InductionInfo* a);
Aart Bikc071a012016-12-01 10:22:31 -0800169 InductionInfo* TransferMul(InductionInfo* a, InductionInfo* b);
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100170 InductionInfo* TransferConversion(InductionInfo* a, DataType::Type from, DataType::Type to);
Aart Bike609b7c2015-08-27 13:46:58 -0700171
172 // Solvers.
Aart Bikd0a022d2016-12-13 11:22:31 -0800173 InductionInfo* SolvePhi(HInstruction* phi, size_t input_index, size_t adjust_input_size);
Aart Bikf475bee2015-09-16 12:50:25 -0700174 InductionInfo* SolvePhiAllInputs(HLoopInformation* loop,
175 HInstruction* entry_phi,
176 HInstruction* phi);
Aart Bike609b7c2015-08-27 13:46:58 -0700177 InductionInfo* SolveAddSub(HLoopInformation* loop,
Aart Bikf475bee2015-09-16 12:50:25 -0700178 HInstruction* entry_phi,
Aart Bike609b7c2015-08-27 13:46:58 -0700179 HInstruction* instruction,
180 HInstruction* x,
181 HInstruction* y,
182 InductionOp op,
Aart Bik7dc96932016-10-12 10:01:05 -0700183 bool is_first_call); // possibly swaps x and y to try again
Aart Bikdf7822e2016-12-06 10:05:30 -0800184 InductionInfo* SolveOp(HLoopInformation* loop,
185 HInstruction* entry_phi,
186 HInstruction* instruction,
187 HInstruction* x,
188 HInstruction* y,
189 InductionOp op);
Aart Bik639cc8c2016-10-18 13:03:31 -0700190 InductionInfo* SolveTest(HLoopInformation* loop,
191 HInstruction* entry_phi,
192 HInstruction* instruction,
193 int64_t oppositive_value);
Aart Bike6bd0272016-12-16 13:57:52 -0800194 InductionInfo* SolveConversion(HLoopInformation* loop,
195 HInstruction* entry_phi,
196 HTypeConversion* conversion);
Aart Bik30efb4e2015-07-30 12:14:31 -0700197
Aart Bikceb06932017-11-13 10:31:17 -0800198 //
199 // Loop trip count analysis methods.
200 //
201
Aart Bikd14c5952015-09-08 15:25:15 -0700202 // Trip count information.
203 void VisitControl(HLoopInformation* loop);
204 void VisitCondition(HLoopInformation* loop,
Aart Bikceb06932017-11-13 10:31:17 -0800205 HBasicBlock* body,
Aart Bikd14c5952015-09-08 15:25:15 -0700206 InductionInfo* a,
207 InductionInfo* b,
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100208 DataType::Type type,
Aart Bikd14c5952015-09-08 15:25:15 -0700209 IfCondition cmp);
210 void VisitTripCount(HLoopInformation* loop,
Aart Bik9401f532015-09-28 16:25:56 -0700211 InductionInfo* lower_expr,
212 InductionInfo* upper_expr,
Aart Bikd14c5952015-09-08 15:25:15 -0700213 InductionInfo* stride,
Aart Bik9401f532015-09-28 16:25:56 -0700214 int64_t stride_value,
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100215 DataType::Type type,
Aart Bikf475bee2015-09-16 12:50:25 -0700216 IfCondition cmp);
Aart Bik9401f532015-09-28 16:25:56 -0700217 bool IsTaken(InductionInfo* lower_expr, InductionInfo* upper_expr, IfCondition cmp);
218 bool IsFinite(InductionInfo* upper_expr,
219 int64_t stride_value,
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100220 DataType::Type type,
Aart Bik9401f532015-09-28 16:25:56 -0700221 IfCondition cmp);
Aart Bik0d345cf2016-03-16 10:49:38 -0700222 bool FitsNarrowerControl(InductionInfo* lower_expr,
223 InductionInfo* upper_expr,
224 int64_t stride_value,
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100225 DataType::Type type,
Aart Bik0d345cf2016-03-16 10:49:38 -0700226 IfCondition cmp);
Aart Bikceb06932017-11-13 10:31:17 -0800227 bool RewriteBreakLoop(HLoopInformation* loop,
228 HBasicBlock* body,
229 int64_t stride_value,
230 DataType::Type type);
231
232 //
233 // Helper methods.
234 //
Aart Bikd14c5952015-09-08 15:25:15 -0700235
Aart Bik30efb4e2015-07-30 12:14:31 -0700236 // Assign and lookup.
Aart Bik30efb4e2015-07-30 12:14:31 -0700237 void AssignInfo(HLoopInformation* loop, HInstruction* instruction, InductionInfo* info);
238 InductionInfo* LookupInfo(HLoopInformation* loop, HInstruction* instruction);
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100239 InductionInfo* CreateConstant(int64_t value, DataType::Type type);
Aart Bik471a2032015-09-04 18:22:11 -0700240 InductionInfo* CreateSimplifiedInvariant(InductionOp op, InductionInfo* a, InductionInfo* b);
Aart Bikd0a022d2016-12-13 11:22:31 -0800241 HInstruction* GetShiftConstant(HLoopInformation* loop,
242 HInstruction* instruction,
243 InductionInfo* initial);
Aart Bikcc42be02016-10-20 16:14:16 -0700244 void AssignCycle(HPhi* phi);
245 ArenaSet<HInstruction*>* LookupCycle(HPhi* phi);
Aart Bik30efb4e2015-07-30 12:14:31 -0700246
Aart Bik7d57d7f2015-12-09 14:39:48 -0800247 // Constants.
Aart Bik97412c92016-02-19 20:14:38 -0800248 bool IsExact(InductionInfo* info, /*out*/ int64_t* value);
249 bool IsAtMost(InductionInfo* info, /*out*/ int64_t* value);
250 bool IsAtLeast(InductionInfo* info, /*out*/ int64_t* value);
Aart Bik7d57d7f2015-12-09 14:39:48 -0800251
Aart Bike609b7c2015-08-27 13:46:58 -0700252 // Helpers.
Aart Bike6bd0272016-12-16 13:57:52 -0800253 static bool IsNarrowingLinear(InductionInfo* info);
Aart Bike609b7c2015-08-27 13:46:58 -0700254 static bool InductionEqual(InductionInfo* info1, InductionInfo* info2);
Aart Bikc071a012016-12-01 10:22:31 -0800255 static std::string FetchToString(HInstruction* fetch);
Aart Bike609b7c2015-08-27 13:46:58 -0700256 static std::string InductionToString(InductionInfo* info);
Aart Bik30efb4e2015-07-30 12:14:31 -0700257
Aart Bike609b7c2015-08-27 13:46:58 -0700258 // TODO: fine tune the following data structures, only keep relevant data.
259
260 // Temporary book-keeping during the analysis.
Aart Bik30efb4e2015-07-30 12:14:31 -0700261 uint32_t global_depth_;
Aart Bik30efb4e2015-07-30 12:14:31 -0700262 ArenaVector<HInstruction*> stack_;
Aart Bike609b7c2015-08-27 13:46:58 -0700263 ArenaSafeMap<HInstruction*, NodeInfo> map_;
Aart Bik7dc96932016-10-12 10:01:05 -0700264 ArenaVector<HInstruction*> scc_;
Aart Bike609b7c2015-08-27 13:46:58 -0700265 ArenaSafeMap<HInstruction*, InductionInfo*> cycle_;
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100266 DataType::Type type_;
Aart Bik30efb4e2015-07-30 12:14:31 -0700267
Aart Bike609b7c2015-08-27 13:46:58 -0700268 /**
269 * Maintains the results of the analysis as a mapping from loops to a mapping from instructions
270 * to the induction information for that instruction in that loop.
271 */
272 ArenaSafeMap<HLoopInformation*, ArenaSafeMap<HInstruction*, InductionInfo*>> induction_;
Aart Bik30efb4e2015-07-30 12:14:31 -0700273
Aart Bikcc42be02016-10-20 16:14:16 -0700274 /**
275 * Preserves induction cycle information for each loop-phi.
276 */
277 ArenaSafeMap<HPhi*, ArenaSet<HInstruction*>> cycles_;
278
Aart Bike609b7c2015-08-27 13:46:58 -0700279 friend class InductionVarAnalysisTest;
Aart Bikd14c5952015-09-08 15:25:15 -0700280 friend class InductionVarRange;
281 friend class InductionVarRangeTest;
Aart Bik30efb4e2015-07-30 12:14:31 -0700282
283 DISALLOW_COPY_AND_ASSIGN(HInductionVarAnalysis);
284};
285
286} // namespace art
287
288#endif // ART_COMPILER_OPTIMIZING_INDUCTION_VAR_ANALYSIS_H_