xref: /aosp_15_r20/art/compiler/optimizing/induction_var_analysis.h (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker  * Copyright (C) 2015 The Android Open Source Project
3*795d594fSAndroid Build Coastguard Worker  *
4*795d594fSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*795d594fSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*795d594fSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*795d594fSAndroid Build Coastguard Worker  *
8*795d594fSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*795d594fSAndroid Build Coastguard Worker  *
10*795d594fSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*795d594fSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*795d594fSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*795d594fSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*795d594fSAndroid Build Coastguard Worker  * limitations under the License.
15*795d594fSAndroid Build Coastguard Worker  */
16*795d594fSAndroid Build Coastguard Worker 
17*795d594fSAndroid Build Coastguard Worker #ifndef ART_COMPILER_OPTIMIZING_INDUCTION_VAR_ANALYSIS_H_
18*795d594fSAndroid Build Coastguard Worker #define ART_COMPILER_OPTIMIZING_INDUCTION_VAR_ANALYSIS_H_
19*795d594fSAndroid Build Coastguard Worker 
20*795d594fSAndroid Build Coastguard Worker #include <string>
21*795d594fSAndroid Build Coastguard Worker 
22*795d594fSAndroid Build Coastguard Worker #include "base/arena_containers.h"
23*795d594fSAndroid Build Coastguard Worker #include "base/array_ref.h"
24*795d594fSAndroid Build Coastguard Worker #include "base/macros.h"
25*795d594fSAndroid Build Coastguard Worker #include "base/scoped_arena_containers.h"
26*795d594fSAndroid Build Coastguard Worker #include "nodes.h"
27*795d594fSAndroid Build Coastguard Worker #include "optimization.h"
28*795d594fSAndroid Build Coastguard Worker 
29*795d594fSAndroid Build Coastguard Worker namespace art HIDDEN {
30*795d594fSAndroid Build Coastguard Worker 
31*795d594fSAndroid Build Coastguard Worker /**
32*795d594fSAndroid Build Coastguard Worker  * Induction variable analysis. This class does not have a direct public API.
33*795d594fSAndroid Build Coastguard Worker  * Instead, the results of induction variable analysis can be queried through
34*795d594fSAndroid Build Coastguard Worker  * friend classes, such as InductionVarRange.
35*795d594fSAndroid Build Coastguard Worker  *
36*795d594fSAndroid Build Coastguard Worker  * The analysis implementation is based on the paper by M. Gerlek et al.
37*795d594fSAndroid Build Coastguard Worker  * "Beyond Induction Variables: Detecting and Classifying Sequences Using a Demand-Driven SSA Form"
38*795d594fSAndroid Build Coastguard Worker  * (ACM Transactions on Programming Languages and Systems, Volume 17 Issue 1, Jan. 1995).
39*795d594fSAndroid Build Coastguard Worker  */
40*795d594fSAndroid Build Coastguard Worker class HInductionVarAnalysis : public HOptimization {
41*795d594fSAndroid Build Coastguard Worker  public:
42*795d594fSAndroid Build Coastguard Worker   explicit HInductionVarAnalysis(HGraph* graph,
43*795d594fSAndroid Build Coastguard Worker                                  OptimizingCompilerStats* stats = nullptr,
44*795d594fSAndroid Build Coastguard Worker                                  const char* name = kInductionPassName);
45*795d594fSAndroid Build Coastguard Worker 
46*795d594fSAndroid Build Coastguard Worker   bool Run() override;
47*795d594fSAndroid Build Coastguard Worker 
48*795d594fSAndroid Build Coastguard Worker   static constexpr const char* kInductionPassName = "induction_var_analysis";
49*795d594fSAndroid Build Coastguard Worker 
50*795d594fSAndroid Build Coastguard Worker  private:
51*795d594fSAndroid Build Coastguard Worker   struct NodeInfo;
52*795d594fSAndroid Build Coastguard Worker   struct StackEntry;
53*795d594fSAndroid Build Coastguard Worker 
54*795d594fSAndroid Build Coastguard Worker   enum InductionClass {
55*795d594fSAndroid Build Coastguard Worker     kInvariant,
56*795d594fSAndroid Build Coastguard Worker     kLinear,
57*795d594fSAndroid Build Coastguard Worker     kPolynomial,
58*795d594fSAndroid Build Coastguard Worker     kGeometric,
59*795d594fSAndroid Build Coastguard Worker     kWrapAround,
60*795d594fSAndroid Build Coastguard Worker     kPeriodic
61*795d594fSAndroid Build Coastguard Worker   };
62*795d594fSAndroid Build Coastguard Worker 
63*795d594fSAndroid Build Coastguard Worker   enum InductionOp {
64*795d594fSAndroid Build Coastguard Worker     // Operations.
65*795d594fSAndroid Build Coastguard Worker     kNop,
66*795d594fSAndroid Build Coastguard Worker     kAdd,
67*795d594fSAndroid Build Coastguard Worker     kSub,
68*795d594fSAndroid Build Coastguard Worker     kNeg,
69*795d594fSAndroid Build Coastguard Worker     kMul,
70*795d594fSAndroid Build Coastguard Worker     kDiv,
71*795d594fSAndroid Build Coastguard Worker     kRem,
72*795d594fSAndroid Build Coastguard Worker     kXor,
73*795d594fSAndroid Build Coastguard Worker     kFetch,
74*795d594fSAndroid Build Coastguard Worker     // Trip-counts.
75*795d594fSAndroid Build Coastguard Worker     kTripCountInLoop,        // valid in full loop; loop is finite
76*795d594fSAndroid Build Coastguard Worker     kTripCountInBody,        // valid in body only; loop is finite
77*795d594fSAndroid Build Coastguard Worker     kTripCountInLoopUnsafe,  // valid in full loop; loop may be infinite
78*795d594fSAndroid Build Coastguard Worker     kTripCountInBodyUnsafe,  // valid in body only; loop may be infinite
79*795d594fSAndroid Build Coastguard Worker     // Comparisons for trip-count tests.
80*795d594fSAndroid Build Coastguard Worker     kLT,
81*795d594fSAndroid Build Coastguard Worker     kLE,
82*795d594fSAndroid Build Coastguard Worker     kGT,
83*795d594fSAndroid Build Coastguard Worker     kGE
84*795d594fSAndroid Build Coastguard Worker   };
85*795d594fSAndroid Build Coastguard Worker 
86*795d594fSAndroid Build Coastguard Worker   /**
87*795d594fSAndroid Build Coastguard Worker    * Defines a detected induction as:
88*795d594fSAndroid Build Coastguard Worker    *   (1) invariant:
89*795d594fSAndroid Build Coastguard Worker    *         op: a + b, a - b, -b, a * b, a / b, a % b, a ^ b, fetch
90*795d594fSAndroid Build Coastguard Worker    *   (2) linear:
91*795d594fSAndroid Build Coastguard Worker    *         nop: a * i + b
92*795d594fSAndroid Build Coastguard Worker    *   (3) polynomial:
93*795d594fSAndroid Build Coastguard Worker    *         nop: sum_lt(a) + b, for linear a
94*795d594fSAndroid Build Coastguard Worker    *   (4) geometric:
95*795d594fSAndroid Build Coastguard Worker    *         op: a * fetch^i + b, a * fetch^-i + b
96*795d594fSAndroid Build Coastguard Worker    *   (5) wrap-around
97*795d594fSAndroid Build Coastguard Worker    *         nop: a, then defined by b
98*795d594fSAndroid Build Coastguard Worker    *   (6) periodic
99*795d594fSAndroid Build Coastguard Worker    *         nop: a, then defined by b (repeated when exhausted)
100*795d594fSAndroid Build Coastguard Worker    *   (7) trip-count:
101*795d594fSAndroid Build Coastguard Worker    *         tc: defined by a, taken-test in b
102*795d594fSAndroid Build Coastguard Worker    */
103*795d594fSAndroid Build Coastguard Worker   struct InductionInfo : public ArenaObject<kArenaAllocInductionVarAnalysis> {
InductionInfoInductionInfo104*795d594fSAndroid Build Coastguard Worker     InductionInfo(InductionClass ic,
105*795d594fSAndroid Build Coastguard Worker                   InductionOp op,
106*795d594fSAndroid Build Coastguard Worker                   InductionInfo* a,
107*795d594fSAndroid Build Coastguard Worker                   InductionInfo* b,
108*795d594fSAndroid Build Coastguard Worker                   HInstruction* f,
109*795d594fSAndroid Build Coastguard Worker                   DataType::Type t)
110*795d594fSAndroid Build Coastguard Worker         : induction_class(ic),
111*795d594fSAndroid Build Coastguard Worker           operation(op),
112*795d594fSAndroid Build Coastguard Worker           op_a(a),
113*795d594fSAndroid Build Coastguard Worker           op_b(b),
114*795d594fSAndroid Build Coastguard Worker           fetch(f),
115*795d594fSAndroid Build Coastguard Worker           type(t) {}
116*795d594fSAndroid Build Coastguard Worker     InductionClass induction_class;
117*795d594fSAndroid Build Coastguard Worker     InductionOp operation;
118*795d594fSAndroid Build Coastguard Worker     InductionInfo* op_a;
119*795d594fSAndroid Build Coastguard Worker     InductionInfo* op_b;
120*795d594fSAndroid Build Coastguard Worker     HInstruction* fetch;
121*795d594fSAndroid Build Coastguard Worker     DataType::Type type;  // precision of operation
122*795d594fSAndroid Build Coastguard Worker   };
123*795d594fSAndroid Build Coastguard Worker 
124*795d594fSAndroid Build Coastguard Worker 
CreateInvariantOp(const HBasicBlock * context,const HLoopInformation * loop,InductionOp op,InductionInfo * a,InductionInfo * b)125*795d594fSAndroid Build Coastguard Worker   InductionInfo* CreateInvariantOp(const HBasicBlock* context,
126*795d594fSAndroid Build Coastguard Worker                                    const HLoopInformation* loop,
127*795d594fSAndroid Build Coastguard Worker                                    InductionOp op,
128*795d594fSAndroid Build Coastguard Worker                                    InductionInfo* a,
129*795d594fSAndroid Build Coastguard Worker                                    InductionInfo* b) {
130*795d594fSAndroid Build Coastguard Worker     DCHECK(((op != kNeg && a != nullptr) || (op == kNeg && a == nullptr)) && b != nullptr);
131*795d594fSAndroid Build Coastguard Worker     return CreateSimplifiedInvariant(context, loop, op, a, b);
132*795d594fSAndroid Build Coastguard Worker   }
133*795d594fSAndroid Build Coastguard Worker 
CreateInvariantFetch(HInstruction * f)134*795d594fSAndroid Build Coastguard Worker   InductionInfo* CreateInvariantFetch(HInstruction* f) {
135*795d594fSAndroid Build Coastguard Worker     DCHECK(f != nullptr);
136*795d594fSAndroid Build Coastguard Worker     return new (graph_->GetAllocator())
137*795d594fSAndroid Build Coastguard Worker         InductionInfo(kInvariant, kFetch, nullptr, nullptr, f, f->GetType());
138*795d594fSAndroid Build Coastguard Worker   }
139*795d594fSAndroid Build Coastguard Worker 
CreateTripCount(InductionOp op,InductionInfo * a,InductionInfo * b,DataType::Type type)140*795d594fSAndroid Build Coastguard Worker   InductionInfo* CreateTripCount(InductionOp op,
141*795d594fSAndroid Build Coastguard Worker                                  InductionInfo* a,
142*795d594fSAndroid Build Coastguard Worker                                  InductionInfo* b,
143*795d594fSAndroid Build Coastguard Worker                                  DataType::Type type) {
144*795d594fSAndroid Build Coastguard Worker     DCHECK(a != nullptr && b != nullptr);
145*795d594fSAndroid Build Coastguard Worker     return new (graph_->GetAllocator()) InductionInfo(kInvariant, op, a, b, nullptr, type);
146*795d594fSAndroid Build Coastguard Worker   }
147*795d594fSAndroid Build Coastguard Worker 
CreateInduction(InductionClass ic,InductionOp op,InductionInfo * a,InductionInfo * b,HInstruction * f,DataType::Type type)148*795d594fSAndroid Build Coastguard Worker   InductionInfo* CreateInduction(InductionClass ic,
149*795d594fSAndroid Build Coastguard Worker                                  InductionOp op,
150*795d594fSAndroid Build Coastguard Worker                                  InductionInfo* a,
151*795d594fSAndroid Build Coastguard Worker                                  InductionInfo* b,
152*795d594fSAndroid Build Coastguard Worker                                  HInstruction* f,
153*795d594fSAndroid Build Coastguard Worker                                  DataType::Type type) {
154*795d594fSAndroid Build Coastguard Worker     DCHECK(a != nullptr && b != nullptr);
155*795d594fSAndroid Build Coastguard Worker     return new (graph_->GetAllocator()) InductionInfo(ic, op, a, b, f, type);
156*795d594fSAndroid Build Coastguard Worker   }
157*795d594fSAndroid Build Coastguard Worker 
158*795d594fSAndroid Build Coastguard Worker   // Methods for analysis.
159*795d594fSAndroid Build Coastguard Worker   void VisitLoop(const HLoopInformation* loop);
160*795d594fSAndroid Build Coastguard Worker   size_t TryVisitNodes(const HLoopInformation* loop,
161*795d594fSAndroid Build Coastguard Worker                        HInstruction* start_instruction,
162*795d594fSAndroid Build Coastguard Worker                        size_t global_depth,
163*795d594fSAndroid Build Coastguard Worker                        /*inout*/ ScopedArenaSafeMap<HInstruction*, NodeInfo>* visited_instructions);
164*795d594fSAndroid Build Coastguard Worker   void ExtractScc(ArrayRef<const StackEntry> stack_tail, ScopedArenaVector<HInstruction*>* scc);
165*795d594fSAndroid Build Coastguard Worker   void ClassifyTrivial(const HLoopInformation* loop, HInstruction* instruction);
166*795d594fSAndroid Build Coastguard Worker   void ClassifyNonTrivial(const HLoopInformation* loop, ArrayRef<const StackEntry> stack_tail);
167*795d594fSAndroid Build Coastguard Worker   InductionInfo* RotatePeriodicInduction(InductionInfo* induction,
168*795d594fSAndroid Build Coastguard Worker                                          InductionInfo* last,
169*795d594fSAndroid Build Coastguard Worker                                          DataType::Type type);
170*795d594fSAndroid Build Coastguard Worker 
171*795d594fSAndroid Build Coastguard Worker   // Transfer operations.
172*795d594fSAndroid Build Coastguard Worker   InductionInfo* TransferPhi(const HLoopInformation* loop,
173*795d594fSAndroid Build Coastguard Worker                              HInstruction* phi,
174*795d594fSAndroid Build Coastguard Worker                              size_t input_index,
175*795d594fSAndroid Build Coastguard Worker                              size_t adjust_input_size);
176*795d594fSAndroid Build Coastguard Worker   InductionInfo* TransferAddSub(const HBasicBlock* context,
177*795d594fSAndroid Build Coastguard Worker                                 const HLoopInformation* loop,
178*795d594fSAndroid Build Coastguard Worker                                 InductionInfo* a,
179*795d594fSAndroid Build Coastguard Worker                                 InductionInfo* b,
180*795d594fSAndroid Build Coastguard Worker                                 InductionOp op,
181*795d594fSAndroid Build Coastguard Worker                                 DataType::Type type);
182*795d594fSAndroid Build Coastguard Worker   InductionInfo* TransferNeg(const HBasicBlock* context,
183*795d594fSAndroid Build Coastguard Worker                              const HLoopInformation* loop,
184*795d594fSAndroid Build Coastguard Worker                              InductionInfo* a,
185*795d594fSAndroid Build Coastguard Worker                              DataType::Type type);
186*795d594fSAndroid Build Coastguard Worker   InductionInfo* TransferMul(const HBasicBlock* context,
187*795d594fSAndroid Build Coastguard Worker                              const HLoopInformation* loop,
188*795d594fSAndroid Build Coastguard Worker                              InductionInfo* a,
189*795d594fSAndroid Build Coastguard Worker                              InductionInfo* b,
190*795d594fSAndroid Build Coastguard Worker                              DataType::Type type);
191*795d594fSAndroid Build Coastguard Worker   InductionInfo* TransferConversion(InductionInfo* a, DataType::Type from, DataType::Type to);
192*795d594fSAndroid Build Coastguard Worker 
193*795d594fSAndroid Build Coastguard Worker   // Solvers.
194*795d594fSAndroid Build Coastguard Worker   InductionInfo* SolvePhi(HInstruction* phi,
195*795d594fSAndroid Build Coastguard Worker                           size_t input_index,
196*795d594fSAndroid Build Coastguard Worker                           size_t adjust_input_size,
197*795d594fSAndroid Build Coastguard Worker                           const ScopedArenaSafeMap<HInstruction*, InductionInfo*>& cycle);
198*795d594fSAndroid Build Coastguard Worker   InductionInfo* SolvePhiAllInputs(const HLoopInformation* loop,
199*795d594fSAndroid Build Coastguard Worker                                    HInstruction* entry_phi,
200*795d594fSAndroid Build Coastguard Worker                                    HInstruction* phi,
201*795d594fSAndroid Build Coastguard Worker                                    const ScopedArenaSafeMap<HInstruction*, InductionInfo*>& cycle,
202*795d594fSAndroid Build Coastguard Worker                                    DataType::Type type);
203*795d594fSAndroid Build Coastguard Worker   InductionInfo* SolveAddSub(const HLoopInformation* loop,
204*795d594fSAndroid Build Coastguard Worker                              HInstruction* entry_phi,
205*795d594fSAndroid Build Coastguard Worker                              HInstruction* instruction,
206*795d594fSAndroid Build Coastguard Worker                              HInstruction* x,
207*795d594fSAndroid Build Coastguard Worker                              HInstruction* y,
208*795d594fSAndroid Build Coastguard Worker                              InductionOp op,
209*795d594fSAndroid Build Coastguard Worker                              const ScopedArenaSafeMap<HInstruction*, InductionInfo*>& cycle,
210*795d594fSAndroid Build Coastguard Worker                              DataType::Type type);
211*795d594fSAndroid Build Coastguard Worker   InductionInfo* SolveOp(const HLoopInformation* loop,
212*795d594fSAndroid Build Coastguard Worker                          HInstruction* entry_phi,
213*795d594fSAndroid Build Coastguard Worker                          HInstruction* instruction,
214*795d594fSAndroid Build Coastguard Worker                          HInstruction* x,
215*795d594fSAndroid Build Coastguard Worker                          HInstruction* y,
216*795d594fSAndroid Build Coastguard Worker                          InductionOp op,
217*795d594fSAndroid Build Coastguard Worker                          DataType::Type type);
218*795d594fSAndroid Build Coastguard Worker   InductionInfo* SolveTest(const HLoopInformation* loop,
219*795d594fSAndroid Build Coastguard Worker                            HInstruction* entry_phi,
220*795d594fSAndroid Build Coastguard Worker                            HInstruction* instruction,
221*795d594fSAndroid Build Coastguard Worker                            int64_t opposite_value,
222*795d594fSAndroid Build Coastguard Worker                            DataType::Type type);
223*795d594fSAndroid Build Coastguard Worker   InductionInfo* SolveConversion(const HLoopInformation* loop,
224*795d594fSAndroid Build Coastguard Worker                                  HInstruction* entry_phi,
225*795d594fSAndroid Build Coastguard Worker                                  HTypeConversion* conversion,
226*795d594fSAndroid Build Coastguard Worker                                  const ScopedArenaSafeMap<HInstruction*, InductionInfo*>& cycle,
227*795d594fSAndroid Build Coastguard Worker                                  /*inout*/ DataType::Type* type);
228*795d594fSAndroid Build Coastguard Worker 
229*795d594fSAndroid Build Coastguard Worker   //
230*795d594fSAndroid Build Coastguard Worker   // Loop trip count analysis methods.
231*795d594fSAndroid Build Coastguard Worker   //
232*795d594fSAndroid Build Coastguard Worker 
233*795d594fSAndroid Build Coastguard Worker   // Trip count information.
234*795d594fSAndroid Build Coastguard Worker   void VisitControl(const HLoopInformation* loop);
235*795d594fSAndroid Build Coastguard Worker   void VisitCondition(const HBasicBlock* context,
236*795d594fSAndroid Build Coastguard Worker                       const HLoopInformation* loop,
237*795d594fSAndroid Build Coastguard Worker                       HBasicBlock* body,
238*795d594fSAndroid Build Coastguard Worker                       InductionInfo* a,
239*795d594fSAndroid Build Coastguard Worker                       InductionInfo* b,
240*795d594fSAndroid Build Coastguard Worker                       DataType::Type type,
241*795d594fSAndroid Build Coastguard Worker                       IfCondition cmp);
242*795d594fSAndroid Build Coastguard Worker   void VisitTripCount(const HBasicBlock* context,
243*795d594fSAndroid Build Coastguard Worker                       const HLoopInformation* loop,
244*795d594fSAndroid Build Coastguard Worker                       InductionInfo* lower_expr,
245*795d594fSAndroid Build Coastguard Worker                       InductionInfo* upper_expr,
246*795d594fSAndroid Build Coastguard Worker                       InductionInfo* stride,
247*795d594fSAndroid Build Coastguard Worker                       int64_t stride_value,
248*795d594fSAndroid Build Coastguard Worker                       DataType::Type type,
249*795d594fSAndroid Build Coastguard Worker                       IfCondition cmp);
250*795d594fSAndroid Build Coastguard Worker   bool IsTaken(const HBasicBlock* context,
251*795d594fSAndroid Build Coastguard Worker                const HLoopInformation* loop,
252*795d594fSAndroid Build Coastguard Worker                InductionInfo* lower_expr,
253*795d594fSAndroid Build Coastguard Worker                InductionInfo* upper_expr,
254*795d594fSAndroid Build Coastguard Worker                IfCondition cmp);
255*795d594fSAndroid Build Coastguard Worker   bool IsFinite(const HBasicBlock* context,
256*795d594fSAndroid Build Coastguard Worker                 const HLoopInformation* loop,
257*795d594fSAndroid Build Coastguard Worker                 InductionInfo* upper_expr,
258*795d594fSAndroid Build Coastguard Worker                 int64_t stride_value,
259*795d594fSAndroid Build Coastguard Worker                 DataType::Type type,
260*795d594fSAndroid Build Coastguard Worker                 IfCondition cmp);
261*795d594fSAndroid Build Coastguard Worker   bool FitsNarrowerControl(const HBasicBlock* context,
262*795d594fSAndroid Build Coastguard Worker                            const HLoopInformation* loop,
263*795d594fSAndroid Build Coastguard Worker                            InductionInfo* lower_expr,
264*795d594fSAndroid Build Coastguard Worker                            InductionInfo* upper_expr,
265*795d594fSAndroid Build Coastguard Worker                            int64_t stride_value,
266*795d594fSAndroid Build Coastguard Worker                            DataType::Type type,
267*795d594fSAndroid Build Coastguard Worker                            IfCondition cmp);
268*795d594fSAndroid Build Coastguard Worker   bool RewriteBreakLoop(const HBasicBlock* context,
269*795d594fSAndroid Build Coastguard Worker                         const HLoopInformation* loop,
270*795d594fSAndroid Build Coastguard Worker                         HBasicBlock* body,
271*795d594fSAndroid Build Coastguard Worker                         int64_t stride_value,
272*795d594fSAndroid Build Coastguard Worker                         DataType::Type type);
273*795d594fSAndroid Build Coastguard Worker 
274*795d594fSAndroid Build Coastguard Worker   //
275*795d594fSAndroid Build Coastguard Worker   // Helper methods.
276*795d594fSAndroid Build Coastguard Worker   //
277*795d594fSAndroid Build Coastguard Worker 
278*795d594fSAndroid Build Coastguard Worker   // Assign and lookup.
279*795d594fSAndroid Build Coastguard Worker   void AssignInfo(const HLoopInformation* loop, HInstruction* instruction, InductionInfo* info);
280*795d594fSAndroid Build Coastguard Worker   InductionInfo* LookupInfo(const HLoopInformation* loop, HInstruction* instruction);
281*795d594fSAndroid Build Coastguard Worker   InductionInfo* CreateConstant(int64_t value, DataType::Type type);
282*795d594fSAndroid Build Coastguard Worker   InductionInfo* CreateSimplifiedInvariant(const HBasicBlock* context,
283*795d594fSAndroid Build Coastguard Worker                                            const HLoopInformation* loop,
284*795d594fSAndroid Build Coastguard Worker                                            InductionOp op,
285*795d594fSAndroid Build Coastguard Worker                                            InductionInfo* a,
286*795d594fSAndroid Build Coastguard Worker                                            InductionInfo* b);
287*795d594fSAndroid Build Coastguard Worker   HInstruction* GetShiftConstant(const HLoopInformation* loop,
288*795d594fSAndroid Build Coastguard Worker                                  HInstruction* instruction,
289*795d594fSAndroid Build Coastguard Worker                                  InductionInfo* initial);
290*795d594fSAndroid Build Coastguard Worker   void AssignCycle(HPhi* phi, ArrayRef<HInstruction* const> scc);
291*795d594fSAndroid Build Coastguard Worker   ArenaSet<HInstruction*>* LookupCycle(HPhi* phi);
292*795d594fSAndroid Build Coastguard Worker 
293*795d594fSAndroid Build Coastguard Worker   // Constants.
294*795d594fSAndroid Build Coastguard Worker   bool IsExact(const HBasicBlock* context,
295*795d594fSAndroid Build Coastguard Worker                const HLoopInformation* loop,
296*795d594fSAndroid Build Coastguard Worker                InductionInfo* info,
297*795d594fSAndroid Build Coastguard Worker                /*out*/int64_t* value);
298*795d594fSAndroid Build Coastguard Worker   bool IsAtMost(const HBasicBlock* context,
299*795d594fSAndroid Build Coastguard Worker                 const HLoopInformation* loop,
300*795d594fSAndroid Build Coastguard Worker                 InductionInfo* info,
301*795d594fSAndroid Build Coastguard Worker                 /*out*/int64_t* value);
302*795d594fSAndroid Build Coastguard Worker   bool IsAtLeast(const HBasicBlock* context,
303*795d594fSAndroid Build Coastguard Worker                  const HLoopInformation* loop,
304*795d594fSAndroid Build Coastguard Worker                  InductionInfo* info,
305*795d594fSAndroid Build Coastguard Worker                  /*out*/int64_t* value);
306*795d594fSAndroid Build Coastguard Worker 
307*795d594fSAndroid Build Coastguard Worker   // Helpers.
308*795d594fSAndroid Build Coastguard Worker   static bool IsNarrowingLinear(InductionInfo* info);
309*795d594fSAndroid Build Coastguard Worker   static bool InductionEqual(InductionInfo* info1, InductionInfo* info2);
310*795d594fSAndroid Build Coastguard Worker   static std::string FetchToString(HInstruction* fetch);
311*795d594fSAndroid Build Coastguard Worker   static std::string InductionToString(InductionInfo* info);
312*795d594fSAndroid Build Coastguard Worker 
313*795d594fSAndroid Build Coastguard Worker   // Returns true if we have a pathological case we don't want to analyze.
314*795d594fSAndroid Build Coastguard Worker   bool IsPathologicalCase();
315*795d594fSAndroid Build Coastguard Worker   // Starting with initial_phi, it calculates how many loop header phis in a row we have. To do
316*795d594fSAndroid Build Coastguard Worker   // this, we count the loop header phi which are used as an input of other loop header phis. It
317*795d594fSAndroid Build Coastguard Worker   // uses `cached_values` to avoid recomputing results.
318*795d594fSAndroid Build Coastguard Worker   void CalculateLoopHeaderPhisInARow(HPhi* initial_phi,
319*795d594fSAndroid Build Coastguard Worker                                      ScopedArenaSafeMap<HPhi*, int>& cached_values,
320*795d594fSAndroid Build Coastguard Worker                                      ScopedArenaAllocator& allocator);
321*795d594fSAndroid Build Coastguard Worker 
322*795d594fSAndroid Build Coastguard Worker   /**
323*795d594fSAndroid Build Coastguard Worker    * Maintains the results of the analysis as a mapping from loops to a mapping from instructions
324*795d594fSAndroid Build Coastguard Worker    * to the induction information for that instruction in that loop.
325*795d594fSAndroid Build Coastguard Worker    */
326*795d594fSAndroid Build Coastguard Worker   ArenaSafeMap<const HLoopInformation*, ArenaSafeMap<HInstruction*, InductionInfo*>> induction_;
327*795d594fSAndroid Build Coastguard Worker 
328*795d594fSAndroid Build Coastguard Worker   /**
329*795d594fSAndroid Build Coastguard Worker    * Preserves induction cycle information for each loop-phi.
330*795d594fSAndroid Build Coastguard Worker    */
331*795d594fSAndroid Build Coastguard Worker   ArenaSafeMap<HPhi*, ArenaSet<HInstruction*>> cycles_;
332*795d594fSAndroid Build Coastguard Worker 
333*795d594fSAndroid Build Coastguard Worker   friend class InductionVarAnalysisTest;
334*795d594fSAndroid Build Coastguard Worker   friend class InductionVarRange;
335*795d594fSAndroid Build Coastguard Worker   friend class InductionVarRangeTest;
336*795d594fSAndroid Build Coastguard Worker 
337*795d594fSAndroid Build Coastguard Worker   DISALLOW_COPY_AND_ASSIGN(HInductionVarAnalysis);
338*795d594fSAndroid Build Coastguard Worker };
339*795d594fSAndroid Build Coastguard Worker 
340*795d594fSAndroid Build Coastguard Worker }  // namespace art
341*795d594fSAndroid Build Coastguard Worker 
342*795d594fSAndroid Build Coastguard Worker #endif  // ART_COMPILER_OPTIMIZING_INDUCTION_VAR_ANALYSIS_H_
343