blob: 9669bcc52816c901902415a8dd1f4dbcfbc22781 [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
42 private:
43 static constexpr const char* kInductionPassName = "induction_var_analysis";
44
45 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 Bik9401f532015-09-28 16:25:56 -070067 kFetch,
68 // Trip counts (valid in full loop or only body proper; unsafe implies loop may be infinite).
69 kTripCountInLoop,
70 kTripCountInBody,
71 kTripCountInLoopUnsafe,
72 kTripCountInBodyUnsafe
Aart Bik30efb4e2015-07-30 12:14:31 -070073 };
74
75 /**
76 * Defines a detected induction as:
77 * (1) invariant:
78 * operation: a + b, a - b, -b, a * b, a / b
Aart Bike609b7c2015-08-27 13:46:58 -070079 * or:
Aart Bik30efb4e2015-07-30 12:14:31 -070080 * fetch: fetch from HIR
81 * (2) linear:
82 * nop: a * i + b
83 * (3) wrap-around
84 * nop: a, then defined by b
85 * (4) periodic
86 * nop: a, then defined by b (repeated when exhausted)
Aart Bik9401f532015-09-28 16:25:56 -070087 * (5) trip-count:
88 * tc: defined by b
Aart Bik30efb4e2015-07-30 12:14:31 -070089 */
90 struct InductionInfo : public ArenaObject<kArenaAllocMisc> {
91 InductionInfo(InductionClass ic,
92 InductionOp op,
93 InductionInfo* a,
94 InductionInfo* b,
95 HInstruction* f)
96 : induction_class(ic),
97 operation(op),
98 op_a(a),
99 op_b(b),
100 fetch(f) {}
101 InductionClass induction_class;
102 InductionOp operation;
103 InductionInfo* op_a;
104 InductionInfo* op_b;
105 HInstruction* fetch;
106 };
107
Aart Bike609b7c2015-08-27 13:46:58 -0700108 bool IsVisitedNode(HInstruction* instruction) const {
109 return map_.find(instruction) != map_.end();
Aart Bik30efb4e2015-07-30 12:14:31 -0700110 }
111
Aart Bik471a2032015-09-04 18:22:11 -0700112 InductionInfo* CreateInvariantOp(InductionOp op, InductionInfo* a, InductionInfo* b) {
Aart Bike609b7c2015-08-27 13:46:58 -0700113 DCHECK(((op != kNeg && a != nullptr) || (op == kNeg && a == nullptr)) && b != nullptr);
Aart Bik471a2032015-09-04 18:22:11 -0700114 return CreateSimplifiedInvariant(op, a, b);
Aart Bike609b7c2015-08-27 13:46:58 -0700115 }
116
Aart Bik471a2032015-09-04 18:22:11 -0700117 InductionInfo* CreateInvariantFetch(HInstruction* f) {
Aart Bike609b7c2015-08-27 13:46:58 -0700118 DCHECK(f != nullptr);
119 return new (graph_->GetArena()) InductionInfo(kInvariant, kFetch, nullptr, nullptr, f);
120 }
121
Aart Bik9401f532015-09-28 16:25:56 -0700122 InductionInfo* CreateTripCount(InductionOp op, InductionInfo* b) {
123 return new (graph_->GetArena()) InductionInfo(kInvariant, op, nullptr, b, nullptr);
124 }
125
Aart Bik471a2032015-09-04 18:22:11 -0700126 InductionInfo* CreateInduction(InductionClass ic, InductionInfo* a, InductionInfo* b) {
Aart Bike609b7c2015-08-27 13:46:58 -0700127 DCHECK(a != nullptr && b != nullptr);
128 return new (graph_->GetArena()) InductionInfo(ic, kNop, a, b, nullptr);
Aart Bik30efb4e2015-07-30 12:14:31 -0700129 }
130
131 // Methods for analysis.
132 void VisitLoop(HLoopInformation* loop);
133 void VisitNode(HLoopInformation* loop, HInstruction* instruction);
134 uint32_t VisitDescendant(HLoopInformation* loop, HInstruction* instruction);
135 void ClassifyTrivial(HLoopInformation* loop, HInstruction* instruction);
136 void ClassifyNonTrivial(HLoopInformation* loop);
Aart Bikf475bee2015-09-16 12:50:25 -0700137 InductionInfo* RotatePeriodicInduction(InductionInfo* induction, InductionInfo* last);
Aart Bik30efb4e2015-07-30 12:14:31 -0700138
139 // Transfer operations.
Aart Bikf475bee2015-09-16 12:50:25 -0700140 InductionInfo* TransferPhi(HLoopInformation* loop, HInstruction* phi, size_t input_index);
Aart Bik30efb4e2015-07-30 12:14:31 -0700141 InductionInfo* TransferAddSub(InductionInfo* a, InductionInfo* b, InductionOp op);
142 InductionInfo* TransferMul(InductionInfo* a, InductionInfo* b);
Aart Bikd14c5952015-09-08 15:25:15 -0700143 InductionInfo* TransferShl(InductionInfo* a, InductionInfo* b, Primitive::Type type);
Aart Bik30efb4e2015-07-30 12:14:31 -0700144 InductionInfo* TransferNeg(InductionInfo* a);
Aart Bike609b7c2015-08-27 13:46:58 -0700145
146 // Solvers.
Aart Bikf475bee2015-09-16 12:50:25 -0700147 InductionInfo* SolvePhi(HInstruction* phi, size_t input_index);
148 InductionInfo* SolvePhiAllInputs(HLoopInformation* loop,
149 HInstruction* entry_phi,
150 HInstruction* phi);
Aart Bike609b7c2015-08-27 13:46:58 -0700151 InductionInfo* SolveAddSub(HLoopInformation* loop,
Aart Bikf475bee2015-09-16 12:50:25 -0700152 HInstruction* entry_phi,
Aart Bike609b7c2015-08-27 13:46:58 -0700153 HInstruction* instruction,
154 HInstruction* x,
155 HInstruction* y,
156 InductionOp op,
157 bool is_first_call);
Aart Bik30efb4e2015-07-30 12:14:31 -0700158
Aart Bikd14c5952015-09-08 15:25:15 -0700159 // Trip count information.
160 void VisitControl(HLoopInformation* loop);
161 void VisitCondition(HLoopInformation* loop,
162 InductionInfo* a,
163 InductionInfo* b,
164 Primitive::Type type,
165 IfCondition cmp);
166 void VisitTripCount(HLoopInformation* loop,
Aart Bik9401f532015-09-28 16:25:56 -0700167 InductionInfo* lower_expr,
168 InductionInfo* upper_expr,
Aart Bikd14c5952015-09-08 15:25:15 -0700169 InductionInfo* stride,
Aart Bik9401f532015-09-28 16:25:56 -0700170 int64_t stride_value,
Aart Bikd14c5952015-09-08 15:25:15 -0700171 Primitive::Type type,
Aart Bikf475bee2015-09-16 12:50:25 -0700172 IfCondition cmp);
Aart Bik9401f532015-09-28 16:25:56 -0700173 bool IsTaken(InductionInfo* lower_expr, InductionInfo* upper_expr, IfCondition cmp);
174 bool IsFinite(InductionInfo* upper_expr,
175 int64_t stride_value,
176 Primitive::Type type,
177 IfCondition cmp);
Aart Bikd14c5952015-09-08 15:25:15 -0700178
Aart Bik30efb4e2015-07-30 12:14:31 -0700179 // Assign and lookup.
Aart Bik30efb4e2015-07-30 12:14:31 -0700180 void AssignInfo(HLoopInformation* loop, HInstruction* instruction, InductionInfo* info);
181 InductionInfo* LookupInfo(HLoopInformation* loop, HInstruction* instruction);
Aart Bikd14c5952015-09-08 15:25:15 -0700182 InductionInfo* CreateConstant(int64_t value, Primitive::Type type);
Aart Bik471a2032015-09-04 18:22:11 -0700183 InductionInfo* CreateSimplifiedInvariant(InductionOp op, InductionInfo* a, InductionInfo* b);
Aart Bik30efb4e2015-07-30 12:14:31 -0700184
Aart Bike609b7c2015-08-27 13:46:58 -0700185 // Helpers.
186 static bool InductionEqual(InductionInfo* info1, InductionInfo* info2);
Aart Bik471a2032015-09-04 18:22:11 -0700187 static bool IsIntAndGet(InductionInfo* info, int64_t* value);
Aart Bike609b7c2015-08-27 13:46:58 -0700188 static std::string InductionToString(InductionInfo* info);
Aart Bik30efb4e2015-07-30 12:14:31 -0700189
Aart Bike609b7c2015-08-27 13:46:58 -0700190 // TODO: fine tune the following data structures, only keep relevant data.
191
192 // Temporary book-keeping during the analysis.
Aart Bik30efb4e2015-07-30 12:14:31 -0700193 uint32_t global_depth_;
Aart Bik30efb4e2015-07-30 12:14:31 -0700194 ArenaVector<HInstruction*> stack_;
195 ArenaVector<HInstruction*> scc_;
Aart Bike609b7c2015-08-27 13:46:58 -0700196 ArenaSafeMap<HInstruction*, NodeInfo> map_;
197 ArenaSafeMap<HInstruction*, InductionInfo*> cycle_;
Aart Bik30efb4e2015-07-30 12:14:31 -0700198
Aart Bike609b7c2015-08-27 13:46:58 -0700199 /**
200 * Maintains the results of the analysis as a mapping from loops to a mapping from instructions
201 * to the induction information for that instruction in that loop.
202 */
203 ArenaSafeMap<HLoopInformation*, ArenaSafeMap<HInstruction*, InductionInfo*>> induction_;
Aart Bik30efb4e2015-07-30 12:14:31 -0700204
Aart Bike609b7c2015-08-27 13:46:58 -0700205 friend class InductionVarAnalysisTest;
Aart Bikd14c5952015-09-08 15:25:15 -0700206 friend class InductionVarRange;
207 friend class InductionVarRangeTest;
Aart Bik30efb4e2015-07-30 12:14:31 -0700208
209 DISALLOW_COPY_AND_ASSIGN(HInductionVarAnalysis);
210};
211
212} // namespace art
213
214#endif // ART_COMPILER_OPTIMIZING_INDUCTION_VAR_ANALYSIS_H_