blob: 2279cd00d29990315ae12dac6e400bd4fd77ad5b [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 Markoe2727152019-10-10 10:46:42 +010022#include "base/macros.h"
Aart Bik30efb4e2015-07-30 12:14:31 -070023#include "nodes.h"
24#include "optimization.h"
25
Vladimir Markoe2727152019-10-10 10:46:42 +010026namespace art HIDDEN {
Aart Bik30efb4e2015-07-30 12:14:31 -070027
28/**
Aart Bike609b7c2015-08-27 13:46:58 -070029 * Induction variable analysis. This class does not have a direct public API.
30 * Instead, the results of induction variable analysis can be queried through
31 * friend classes, such as InductionVarRange.
Aart Bik30efb4e2015-07-30 12:14:31 -070032 *
Aart Bike609b7c2015-08-27 13:46:58 -070033 * The analysis implementation is based on the paper by M. Gerlek et al.
Aart Bik30efb4e2015-07-30 12:14:31 -070034 * "Beyond Induction Variables: Detecting and Classifying Sequences Using a Demand-Driven SSA Form"
35 * (ACM Transactions on Programming Languages and Systems, Volume 17 Issue 1, Jan. 1995).
36 */
37class HInductionVarAnalysis : public HOptimization {
38 public:
Aart Bik2ca10eb2017-11-15 15:17:53 -080039 explicit HInductionVarAnalysis(HGraph* graph, const char* name = kInductionPassName);
Aart Bik30efb4e2015-07-30 12:14:31 -070040
Roland Levillainbbc6e7e2018-08-24 16:58:47 +010041 bool Run() override;
Aart Bik30efb4e2015-07-30 12:14:31 -070042
Aart Bik30efb4e2015-07-30 12:14:31 -070043 static constexpr const char* kInductionPassName = "induction_var_analysis";
44
Wojciech Staszkiewicz5319d3c2016-08-01 17:48:59 -070045 private:
Aart Bik30efb4e2015-07-30 12:14:31 -070046 struct NodeInfo {
47 explicit NodeInfo(uint32_t d) : depth(d), done(false) {}
48 uint32_t depth;
49 bool done;
50 };
51
52 enum InductionClass {
Aart Bik30efb4e2015-07-30 12:14:31 -070053 kInvariant,
54 kLinear,
Aart Bikc071a012016-12-01 10:22:31 -080055 kPolynomial,
56 kGeometric,
Aart Bik30efb4e2015-07-30 12:14:31 -070057 kWrapAround,
Aart Bike609b7c2015-08-27 13:46:58 -070058 kPeriodic
Aart Bik30efb4e2015-07-30 12:14:31 -070059 };
60
61 enum InductionOp {
Aart Bikc071a012016-12-01 10:22:31 -080062 // Operations.
Aart Bik9401f532015-09-28 16:25:56 -070063 kNop,
Aart Bik30efb4e2015-07-30 12:14:31 -070064 kAdd,
65 kSub,
66 kNeg,
67 kMul,
68 kDiv,
Aart Bikdf7822e2016-12-06 10:05:30 -080069 kRem,
Aart Bik7dc96932016-10-12 10:01:05 -070070 kXor,
Aart Bik9401f532015-09-28 16:25:56 -070071 kFetch,
Aart Bik22f05872015-10-27 15:56:28 -070072 // Trip-counts.
73 kTripCountInLoop, // valid in full loop; loop is finite
74 kTripCountInBody, // valid in body only; loop is finite
75 kTripCountInLoopUnsafe, // valid in full loop; loop may be infinite
76 kTripCountInBodyUnsafe, // valid in body only; loop may be infinite
77 // Comparisons for trip-count tests.
78 kLT,
79 kLE,
80 kGT,
81 kGE
Aart Bik30efb4e2015-07-30 12:14:31 -070082 };
83
84 /**
85 * Defines a detected induction as:
86 * (1) invariant:
Aart Bikc071a012016-12-01 10:22:31 -080087 * op: a + b, a - b, -b, a * b, a / b, a % b, a ^ b, fetch
Aart Bik30efb4e2015-07-30 12:14:31 -070088 * (2) linear:
89 * nop: a * i + b
Aart Bikdf7822e2016-12-06 10:05:30 -080090 * (3) polynomial:
91 * nop: sum_lt(a) + b, for linear a
Aart Bikc071a012016-12-01 10:22:31 -080092 * (4) geometric:
Aart Bikdf7822e2016-12-06 10:05:30 -080093 * op: a * fetch^i + b, a * fetch^-i + b
Aart Bikc071a012016-12-01 10:22:31 -080094 * (5) wrap-around
Aart Bik30efb4e2015-07-30 12:14:31 -070095 * nop: a, then defined by b
Aart Bikc071a012016-12-01 10:22:31 -080096 * (6) periodic
Aart Bik30efb4e2015-07-30 12:14:31 -070097 * nop: a, then defined by b (repeated when exhausted)
Aart Bikc071a012016-12-01 10:22:31 -080098 * (7) trip-count:
Aart Bik22f05872015-10-27 15:56:28 -070099 * tc: defined by a, taken-test in b
Aart Bik30efb4e2015-07-30 12:14:31 -0700100 */
Vladimir Marko5233f932015-09-29 19:01:15 +0100101 struct InductionInfo : public ArenaObject<kArenaAllocInductionVarAnalysis> {
Aart Bik30efb4e2015-07-30 12:14:31 -0700102 InductionInfo(InductionClass ic,
103 InductionOp op,
104 InductionInfo* a,
105 InductionInfo* b,
Aart Bik0d345cf2016-03-16 10:49:38 -0700106 HInstruction* f,
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100107 DataType::Type t)
Aart Bik30efb4e2015-07-30 12:14:31 -0700108 : induction_class(ic),
109 operation(op),
110 op_a(a),
111 op_b(b),
Aart Bik0d345cf2016-03-16 10:49:38 -0700112 fetch(f),
113 type(t) {}
Aart Bik30efb4e2015-07-30 12:14:31 -0700114 InductionClass induction_class;
115 InductionOp operation;
116 InductionInfo* op_a;
117 InductionInfo* op_b;
118 HInstruction* fetch;
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100119 DataType::Type type; // precision of operation
Aart Bik30efb4e2015-07-30 12:14:31 -0700120 };
121
Aart Bike609b7c2015-08-27 13:46:58 -0700122 bool IsVisitedNode(HInstruction* instruction) const {
123 return map_.find(instruction) != map_.end();
Aart Bik30efb4e2015-07-30 12:14:31 -0700124 }
125
Aart Bik471a2032015-09-04 18:22:11 -0700126 InductionInfo* CreateInvariantOp(InductionOp op, InductionInfo* a, InductionInfo* b) {
Aart Bike609b7c2015-08-27 13:46:58 -0700127 DCHECK(((op != kNeg && a != nullptr) || (op == kNeg && a == nullptr)) && b != nullptr);
Aart Bik471a2032015-09-04 18:22:11 -0700128 return CreateSimplifiedInvariant(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.
156 void VisitLoop(HLoopInformation* loop);
157 void VisitNode(HLoopInformation* loop, HInstruction* instruction);
158 uint32_t VisitDescendant(HLoopInformation* loop, HInstruction* instruction);
159 void ClassifyTrivial(HLoopInformation* loop, HInstruction* instruction);
160 void ClassifyNonTrivial(HLoopInformation* loop);
Aart Bikf475bee2015-09-16 12:50:25 -0700161 InductionInfo* RotatePeriodicInduction(InductionInfo* induction, InductionInfo* last);
Aart Bik30efb4e2015-07-30 12:14:31 -0700162
163 // Transfer operations.
Aart Bikd0a022d2016-12-13 11:22:31 -0800164 InductionInfo* TransferPhi(HLoopInformation* loop,
165 HInstruction* phi,
166 size_t input_index,
167 size_t adjust_input_size);
Aart Bik30efb4e2015-07-30 12:14:31 -0700168 InductionInfo* TransferAddSub(InductionInfo* a, InductionInfo* b, InductionOp op);
Aart Bik30efb4e2015-07-30 12:14:31 -0700169 InductionInfo* TransferNeg(InductionInfo* a);
Aart Bikc071a012016-12-01 10:22:31 -0800170 InductionInfo* TransferMul(InductionInfo* a, InductionInfo* b);
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100171 InductionInfo* TransferConversion(InductionInfo* a, DataType::Type from, DataType::Type to);
Aart Bike609b7c2015-08-27 13:46:58 -0700172
173 // Solvers.
Aart Bikd0a022d2016-12-13 11:22:31 -0800174 InductionInfo* SolvePhi(HInstruction* phi, size_t input_index, size_t adjust_input_size);
Aart Bikf475bee2015-09-16 12:50:25 -0700175 InductionInfo* SolvePhiAllInputs(HLoopInformation* loop,
176 HInstruction* entry_phi,
177 HInstruction* phi);
Aart Bike609b7c2015-08-27 13:46:58 -0700178 InductionInfo* SolveAddSub(HLoopInformation* loop,
Aart Bikf475bee2015-09-16 12:50:25 -0700179 HInstruction* entry_phi,
Aart Bike609b7c2015-08-27 13:46:58 -0700180 HInstruction* instruction,
181 HInstruction* x,
182 HInstruction* y,
183 InductionOp op,
Aart Bik7dc96932016-10-12 10:01:05 -0700184 bool is_first_call); // possibly swaps x and y to try again
Aart Bikdf7822e2016-12-06 10:05:30 -0800185 InductionInfo* SolveOp(HLoopInformation* loop,
186 HInstruction* entry_phi,
187 HInstruction* instruction,
188 HInstruction* x,
189 HInstruction* y,
190 InductionOp op);
Aart Bik639cc8c2016-10-18 13:03:31 -0700191 InductionInfo* SolveTest(HLoopInformation* loop,
192 HInstruction* entry_phi,
193 HInstruction* instruction,
194 int64_t oppositive_value);
Aart Bike6bd0272016-12-16 13:57:52 -0800195 InductionInfo* SolveConversion(HLoopInformation* loop,
196 HInstruction* entry_phi,
197 HTypeConversion* conversion);
Aart Bik30efb4e2015-07-30 12:14:31 -0700198
Aart Bikceb06932017-11-13 10:31:17 -0800199 //
200 // Loop trip count analysis methods.
201 //
202
Aart Bikd14c5952015-09-08 15:25:15 -0700203 // Trip count information.
204 void VisitControl(HLoopInformation* loop);
205 void VisitCondition(HLoopInformation* loop,
Aart Bikceb06932017-11-13 10:31:17 -0800206 HBasicBlock* body,
Aart Bikd14c5952015-09-08 15:25:15 -0700207 InductionInfo* a,
208 InductionInfo* b,
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100209 DataType::Type type,
Aart Bikd14c5952015-09-08 15:25:15 -0700210 IfCondition cmp);
211 void VisitTripCount(HLoopInformation* loop,
Aart Bik9401f532015-09-28 16:25:56 -0700212 InductionInfo* lower_expr,
213 InductionInfo* upper_expr,
Aart Bikd14c5952015-09-08 15:25:15 -0700214 InductionInfo* stride,
Aart Bik9401f532015-09-28 16:25:56 -0700215 int64_t stride_value,
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100216 DataType::Type type,
Aart Bikf475bee2015-09-16 12:50:25 -0700217 IfCondition cmp);
Aart Bik9401f532015-09-28 16:25:56 -0700218 bool IsTaken(InductionInfo* lower_expr, InductionInfo* upper_expr, IfCondition cmp);
219 bool IsFinite(InductionInfo* upper_expr,
220 int64_t stride_value,
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100221 DataType::Type type,
Aart Bik9401f532015-09-28 16:25:56 -0700222 IfCondition cmp);
Aart Bik0d345cf2016-03-16 10:49:38 -0700223 bool FitsNarrowerControl(InductionInfo* lower_expr,
224 InductionInfo* upper_expr,
225 int64_t stride_value,
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100226 DataType::Type type,
Aart Bik0d345cf2016-03-16 10:49:38 -0700227 IfCondition cmp);
Aart Bikceb06932017-11-13 10:31:17 -0800228 bool RewriteBreakLoop(HLoopInformation* loop,
229 HBasicBlock* body,
230 int64_t stride_value,
231 DataType::Type type);
232
233 //
234 // Helper methods.
235 //
Aart Bikd14c5952015-09-08 15:25:15 -0700236
Aart Bik30efb4e2015-07-30 12:14:31 -0700237 // Assign and lookup.
Aart Bik30efb4e2015-07-30 12:14:31 -0700238 void AssignInfo(HLoopInformation* loop, HInstruction* instruction, InductionInfo* info);
239 InductionInfo* LookupInfo(HLoopInformation* loop, HInstruction* instruction);
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100240 InductionInfo* CreateConstant(int64_t value, DataType::Type type);
Aart Bik471a2032015-09-04 18:22:11 -0700241 InductionInfo* CreateSimplifiedInvariant(InductionOp op, InductionInfo* a, InductionInfo* b);
Aart Bikd0a022d2016-12-13 11:22:31 -0800242 HInstruction* GetShiftConstant(HLoopInformation* loop,
243 HInstruction* instruction,
244 InductionInfo* initial);
Aart Bikcc42be02016-10-20 16:14:16 -0700245 void AssignCycle(HPhi* phi);
246 ArenaSet<HInstruction*>* LookupCycle(HPhi* phi);
Aart Bik30efb4e2015-07-30 12:14:31 -0700247
Aart Bik7d57d7f2015-12-09 14:39:48 -0800248 // Constants.
Aart Bik97412c922016-02-19 20:14:38 -0800249 bool IsExact(InductionInfo* info, /*out*/ int64_t* value);
250 bool IsAtMost(InductionInfo* info, /*out*/ int64_t* value);
251 bool IsAtLeast(InductionInfo* info, /*out*/ int64_t* value);
Aart Bik7d57d7f2015-12-09 14:39:48 -0800252
Aart Bike609b7c2015-08-27 13:46:58 -0700253 // Helpers.
Aart Bike6bd0272016-12-16 13:57:52 -0800254 static bool IsNarrowingLinear(InductionInfo* info);
Aart Bike609b7c2015-08-27 13:46:58 -0700255 static bool InductionEqual(InductionInfo* info1, InductionInfo* info2);
Aart Bikc071a012016-12-01 10:22:31 -0800256 static std::string FetchToString(HInstruction* fetch);
Aart Bike609b7c2015-08-27 13:46:58 -0700257 static std::string InductionToString(InductionInfo* info);
Aart Bik30efb4e2015-07-30 12:14:31 -0700258
Aart Bike609b7c2015-08-27 13:46:58 -0700259 // TODO: fine tune the following data structures, only keep relevant data.
260
261 // Temporary book-keeping during the analysis.
Aart Bik30efb4e2015-07-30 12:14:31 -0700262 uint32_t global_depth_;
Aart Bik30efb4e2015-07-30 12:14:31 -0700263 ArenaVector<HInstruction*> stack_;
Aart Bike609b7c2015-08-27 13:46:58 -0700264 ArenaSafeMap<HInstruction*, NodeInfo> map_;
Aart Bik7dc96932016-10-12 10:01:05 -0700265 ArenaVector<HInstruction*> scc_;
Aart Bike609b7c2015-08-27 13:46:58 -0700266 ArenaSafeMap<HInstruction*, InductionInfo*> cycle_;
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100267 DataType::Type type_;
Aart Bik30efb4e2015-07-30 12:14:31 -0700268
Aart Bike609b7c2015-08-27 13:46:58 -0700269 /**
270 * Maintains the results of the analysis as a mapping from loops to a mapping from instructions
271 * to the induction information for that instruction in that loop.
272 */
273 ArenaSafeMap<HLoopInformation*, ArenaSafeMap<HInstruction*, InductionInfo*>> induction_;
Aart Bik30efb4e2015-07-30 12:14:31 -0700274
Aart Bikcc42be02016-10-20 16:14:16 -0700275 /**
276 * Preserves induction cycle information for each loop-phi.
277 */
278 ArenaSafeMap<HPhi*, ArenaSet<HInstruction*>> cycles_;
279
Aart Bike609b7c2015-08-27 13:46:58 -0700280 friend class InductionVarAnalysisTest;
Aart Bikd14c5952015-09-08 15:25:15 -0700281 friend class InductionVarRange;
282 friend class InductionVarRangeTest;
Aart Bik30efb4e2015-07-30 12:14:31 -0700283
284 DISALLOW_COPY_AND_ASSIGN(HInductionVarAnalysis);
285};
286
287} // namespace art
288
289#endif // ART_COMPILER_OPTIMIZING_INDUCTION_VAR_ANALYSIS_H_