blob: 70271799d23524dd3e6ad8ca3239c89fbee0798b [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:
38 explicit HInductionVarAnalysis(HGraph* graph);
39
Aart Bik30efb4e2015-07-30 12:14:31 -070040 void Run() OVERRIDE;
41
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,
54 kWrapAround,
Aart Bike609b7c2015-08-27 13:46:58 -070055 kPeriodic
Aart Bik30efb4e2015-07-30 12:14:31 -070056 };
57
58 enum InductionOp {
Aart Bik9401f532015-09-28 16:25:56 -070059 // No-operation: a true induction.
60 kNop,
61 // Various invariant operations.
Aart Bik30efb4e2015-07-30 12:14:31 -070062 kAdd,
63 kSub,
64 kNeg,
65 kMul,
66 kDiv,
Aart Bik7dc96932016-10-12 10:01:05 -070067 kXor,
Aart Bik9401f532015-09-28 16:25:56 -070068 kFetch,
Aart Bik22f05872015-10-27 15:56:28 -070069 // Trip-counts.
70 kTripCountInLoop, // valid in full loop; loop is finite
71 kTripCountInBody, // valid in body only; loop is finite
72 kTripCountInLoopUnsafe, // valid in full loop; loop may be infinite
73 kTripCountInBodyUnsafe, // valid in body only; loop may be infinite
74 // Comparisons for trip-count tests.
75 kLT,
76 kLE,
77 kGT,
78 kGE
Aart Bik30efb4e2015-07-30 12:14:31 -070079 };
80
81 /**
82 * Defines a detected induction as:
83 * (1) invariant:
84 * operation: a + b, a - b, -b, a * b, a / b
Aart Bike609b7c2015-08-27 13:46:58 -070085 * or:
Aart Bik30efb4e2015-07-30 12:14:31 -070086 * fetch: fetch from HIR
87 * (2) linear:
88 * nop: a * i + b
89 * (3) wrap-around
90 * nop: a, then defined by b
91 * (4) periodic
92 * nop: a, then defined by b (repeated when exhausted)
Aart Bik9401f532015-09-28 16:25:56 -070093 * (5) trip-count:
Aart Bik22f05872015-10-27 15:56:28 -070094 * tc: defined by a, taken-test in b
Aart Bik30efb4e2015-07-30 12:14:31 -070095 */
Vladimir Marko5233f932015-09-29 19:01:15 +010096 struct InductionInfo : public ArenaObject<kArenaAllocInductionVarAnalysis> {
Aart Bik30efb4e2015-07-30 12:14:31 -070097 InductionInfo(InductionClass ic,
98 InductionOp op,
99 InductionInfo* a,
100 InductionInfo* b,
Aart Bik0d345cf2016-03-16 10:49:38 -0700101 HInstruction* f,
102 Primitive::Type t)
Aart Bik30efb4e2015-07-30 12:14:31 -0700103 : induction_class(ic),
104 operation(op),
105 op_a(a),
106 op_b(b),
Aart Bik0d345cf2016-03-16 10:49:38 -0700107 fetch(f),
108 type(t) {}
Aart Bik30efb4e2015-07-30 12:14:31 -0700109 InductionClass induction_class;
110 InductionOp operation;
111 InductionInfo* op_a;
112 InductionInfo* op_b;
113 HInstruction* fetch;
Aart Bik0d345cf2016-03-16 10:49:38 -0700114 Primitive::Type type; // precision of induction
Aart Bik30efb4e2015-07-30 12:14:31 -0700115 };
116
Aart Bike609b7c2015-08-27 13:46:58 -0700117 bool IsVisitedNode(HInstruction* instruction) const {
118 return map_.find(instruction) != map_.end();
Aart Bik30efb4e2015-07-30 12:14:31 -0700119 }
120
Aart Bik471a2032015-09-04 18:22:11 -0700121 InductionInfo* CreateInvariantOp(InductionOp op, InductionInfo* a, InductionInfo* b) {
Aart Bike609b7c2015-08-27 13:46:58 -0700122 DCHECK(((op != kNeg && a != nullptr) || (op == kNeg && a == nullptr)) && b != nullptr);
Aart Bik471a2032015-09-04 18:22:11 -0700123 return CreateSimplifiedInvariant(op, a, b);
Aart Bike609b7c2015-08-27 13:46:58 -0700124 }
125
Aart Bik471a2032015-09-04 18:22:11 -0700126 InductionInfo* CreateInvariantFetch(HInstruction* f) {
Aart Bike609b7c2015-08-27 13:46:58 -0700127 DCHECK(f != nullptr);
Aart Bik0d345cf2016-03-16 10:49:38 -0700128 return new (graph_->GetArena())
129 InductionInfo(kInvariant, kFetch, nullptr, nullptr, f, f->GetType());
Aart Bike609b7c2015-08-27 13:46:58 -0700130 }
131
Aart Bik0d345cf2016-03-16 10:49:38 -0700132 InductionInfo* CreateTripCount(InductionOp op,
133 InductionInfo* a,
134 InductionInfo* b,
135 Primitive::Type type) {
Aart Bik52be7e72016-06-23 11:20:41 -0700136 DCHECK(a != nullptr && b != nullptr);
Aart Bik0d345cf2016-03-16 10:49:38 -0700137 return new (graph_->GetArena()) InductionInfo(kInvariant, op, a, b, nullptr, type);
Aart Bik9401f532015-09-28 16:25:56 -0700138 }
139
Aart Bik0d345cf2016-03-16 10:49:38 -0700140 InductionInfo* CreateInduction(InductionClass ic,
141 InductionInfo* a,
142 InductionInfo* b,
143 Primitive::Type type) {
Aart Bike609b7c2015-08-27 13:46:58 -0700144 DCHECK(a != nullptr && b != nullptr);
Aart Bik0d345cf2016-03-16 10:49:38 -0700145 return new (graph_->GetArena()) InductionInfo(ic, kNop, a, b, nullptr, type);
Aart Bik30efb4e2015-07-30 12:14:31 -0700146 }
147
148 // Methods for analysis.
149 void VisitLoop(HLoopInformation* loop);
150 void VisitNode(HLoopInformation* loop, HInstruction* instruction);
151 uint32_t VisitDescendant(HLoopInformation* loop, HInstruction* instruction);
152 void ClassifyTrivial(HLoopInformation* loop, HInstruction* instruction);
153 void ClassifyNonTrivial(HLoopInformation* loop);
Aart Bikf475bee2015-09-16 12:50:25 -0700154 InductionInfo* RotatePeriodicInduction(InductionInfo* induction, InductionInfo* last);
Aart Bik30efb4e2015-07-30 12:14:31 -0700155
156 // Transfer operations.
Aart Bikf475bee2015-09-16 12:50:25 -0700157 InductionInfo* TransferPhi(HLoopInformation* loop, HInstruction* phi, size_t input_index);
Aart Bik30efb4e2015-07-30 12:14:31 -0700158 InductionInfo* TransferAddSub(InductionInfo* a, InductionInfo* b, InductionOp op);
159 InductionInfo* TransferMul(InductionInfo* a, InductionInfo* b);
Aart Bikd14c5952015-09-08 15:25:15 -0700160 InductionInfo* TransferShl(InductionInfo* a, InductionInfo* b, Primitive::Type type);
Aart Bik30efb4e2015-07-30 12:14:31 -0700161 InductionInfo* TransferNeg(InductionInfo* a);
Aart Bik0d345cf2016-03-16 10:49:38 -0700162 InductionInfo* TransferCnv(InductionInfo* a, Primitive::Type from, Primitive::Type to);
Aart Bike609b7c2015-08-27 13:46:58 -0700163
164 // Solvers.
Aart Bikf475bee2015-09-16 12:50:25 -0700165 InductionInfo* SolvePhi(HInstruction* phi, size_t input_index);
166 InductionInfo* SolvePhiAllInputs(HLoopInformation* loop,
167 HInstruction* entry_phi,
168 HInstruction* phi);
Aart Bike609b7c2015-08-27 13:46:58 -0700169 InductionInfo* SolveAddSub(HLoopInformation* loop,
Aart Bikf475bee2015-09-16 12:50:25 -0700170 HInstruction* entry_phi,
Aart Bike609b7c2015-08-27 13:46:58 -0700171 HInstruction* instruction,
172 HInstruction* x,
173 HInstruction* y,
174 InductionOp op,
Aart Bik7dc96932016-10-12 10:01:05 -0700175 bool is_first_call); // possibly swaps x and y to try again
176 InductionInfo* SolveXor(HLoopInformation* loop,
177 HInstruction* entry_phi,
178 HInstruction* instruction,
179 HInstruction* x,
Aart Bik639cc8c2016-10-18 13:03:31 -0700180 HInstruction* y);
181 InductionInfo* SolveTest(HLoopInformation* loop,
182 HInstruction* entry_phi,
183 HInstruction* instruction,
184 int64_t oppositive_value);
Aart Bik0d345cf2016-03-16 10:49:38 -0700185 InductionInfo* SolveCnv(HTypeConversion* conversion);
Aart Bik30efb4e2015-07-30 12:14:31 -0700186
Aart Bikd14c5952015-09-08 15:25:15 -0700187 // Trip count information.
188 void VisitControl(HLoopInformation* loop);
189 void VisitCondition(HLoopInformation* loop,
190 InductionInfo* a,
191 InductionInfo* b,
192 Primitive::Type type,
193 IfCondition cmp);
194 void VisitTripCount(HLoopInformation* loop,
Aart Bik9401f532015-09-28 16:25:56 -0700195 InductionInfo* lower_expr,
196 InductionInfo* upper_expr,
Aart Bikd14c5952015-09-08 15:25:15 -0700197 InductionInfo* stride,
Aart Bik9401f532015-09-28 16:25:56 -0700198 int64_t stride_value,
Aart Bikd14c5952015-09-08 15:25:15 -0700199 Primitive::Type type,
Aart Bikf475bee2015-09-16 12:50:25 -0700200 IfCondition cmp);
Aart Bik9401f532015-09-28 16:25:56 -0700201 bool IsTaken(InductionInfo* lower_expr, InductionInfo* upper_expr, IfCondition cmp);
202 bool IsFinite(InductionInfo* upper_expr,
203 int64_t stride_value,
204 Primitive::Type type,
205 IfCondition cmp);
Aart Bik0d345cf2016-03-16 10:49:38 -0700206 bool FitsNarrowerControl(InductionInfo* lower_expr,
207 InductionInfo* upper_expr,
208 int64_t stride_value,
209 Primitive::Type type,
210 IfCondition cmp);
Aart Bikd14c5952015-09-08 15:25:15 -0700211
Aart Bik30efb4e2015-07-30 12:14:31 -0700212 // Assign and lookup.
Aart Bik30efb4e2015-07-30 12:14:31 -0700213 void AssignInfo(HLoopInformation* loop, HInstruction* instruction, InductionInfo* info);
214 InductionInfo* LookupInfo(HLoopInformation* loop, HInstruction* instruction);
Aart Bikd14c5952015-09-08 15:25:15 -0700215 InductionInfo* CreateConstant(int64_t value, Primitive::Type type);
Aart Bik471a2032015-09-04 18:22:11 -0700216 InductionInfo* CreateSimplifiedInvariant(InductionOp op, InductionInfo* a, InductionInfo* b);
Aart Bikcc42be02016-10-20 16:14:16 -0700217 void AssignCycle(HPhi* phi);
218 ArenaSet<HInstruction*>* LookupCycle(HPhi* phi);
Aart Bik30efb4e2015-07-30 12:14:31 -0700219
Aart Bik7d57d7f2015-12-09 14:39:48 -0800220 // Constants.
Aart Bik97412c92016-02-19 20:14:38 -0800221 bool IsExact(InductionInfo* info, /*out*/ int64_t* value);
222 bool IsAtMost(InductionInfo* info, /*out*/ int64_t* value);
223 bool IsAtLeast(InductionInfo* info, /*out*/ int64_t* value);
Aart Bik7d57d7f2015-12-09 14:39:48 -0800224
Aart Bike609b7c2015-08-27 13:46:58 -0700225 // Helpers.
226 static bool InductionEqual(InductionInfo* info1, InductionInfo* info2);
227 static std::string InductionToString(InductionInfo* info);
Aart Bik30efb4e2015-07-30 12:14:31 -0700228
Aart Bike609b7c2015-08-27 13:46:58 -0700229 // TODO: fine tune the following data structures, only keep relevant data.
230
231 // Temporary book-keeping during the analysis.
Aart Bik30efb4e2015-07-30 12:14:31 -0700232 uint32_t global_depth_;
Aart Bik30efb4e2015-07-30 12:14:31 -0700233 ArenaVector<HInstruction*> stack_;
Aart Bike609b7c2015-08-27 13:46:58 -0700234 ArenaSafeMap<HInstruction*, NodeInfo> map_;
Aart Bik7dc96932016-10-12 10:01:05 -0700235 ArenaVector<HInstruction*> scc_;
Aart Bike609b7c2015-08-27 13:46:58 -0700236 ArenaSafeMap<HInstruction*, InductionInfo*> cycle_;
Aart Bik0d345cf2016-03-16 10:49:38 -0700237 Primitive::Type type_;
Aart Bik30efb4e2015-07-30 12:14:31 -0700238
Aart Bike609b7c2015-08-27 13:46:58 -0700239 /**
240 * Maintains the results of the analysis as a mapping from loops to a mapping from instructions
241 * to the induction information for that instruction in that loop.
242 */
243 ArenaSafeMap<HLoopInformation*, ArenaSafeMap<HInstruction*, InductionInfo*>> induction_;
Aart Bik30efb4e2015-07-30 12:14:31 -0700244
Aart Bikcc42be02016-10-20 16:14:16 -0700245 /**
246 * Preserves induction cycle information for each loop-phi.
247 */
248 ArenaSafeMap<HPhi*, ArenaSet<HInstruction*>> cycles_;
249
Aart Bike609b7c2015-08-27 13:46:58 -0700250 friend class InductionVarAnalysisTest;
Aart Bikd14c5952015-09-08 15:25:15 -0700251 friend class InductionVarRange;
252 friend class InductionVarRangeTest;
Aart Bik30efb4e2015-07-30 12:14:31 -0700253
254 DISALLOW_COPY_AND_ASSIGN(HInductionVarAnalysis);
255};
256
257} // namespace art
258
259#endif // ART_COMPILER_OPTIMIZING_INDUCTION_VAR_ANALYSIS_H_