• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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_RANGE_H_
18 #define ART_COMPILER_OPTIMIZING_INDUCTION_VAR_RANGE_H_
19 
20 #include "induction_var_analysis.h"
21 
22 namespace art {
23 
24 /**
25  * This class implements range analysis on expressions within loops. It takes the results
26  * of induction variable analysis in the constructor and provides a public API to obtain
27  * a conservative lower and upper bound value on each instruction in the HIR.
28  *
29  * The range analysis is done with a combination of symbolic and partial integral evaluation
30  * of expressions. The analysis avoids complications with wrap-around arithmetic on the integral
31  * parts but all clients should be aware that wrap-around may occur on any of the symbolic parts.
32  * For example, given a known range for [0,100] for i, the evaluation yields range [-100,100]
33  * for expression -2*i+100, which is exact, and range [x,x+100] for expression i+x, which may
34  * wrap-around anywhere in the range depending on the actual value of x.
35  */
36 class InductionVarRange {
37  public:
38   /*
39    * A value that can be represented as "a * instruction + b" for 32-bit constants, where
40    * Value() denotes an unknown lower and upper bound. Although range analysis could yield
41    * more complex values, the format is sufficiently powerful to represent useful cases
42    * and feeds directly into optimizations like bounds check elimination.
43    */
44   struct Value {
ValueValue45     Value() : instruction(nullptr), a_constant(0), b_constant(0), is_known(false) {}
ValueValue46     Value(HInstruction* i, int32_t a, int32_t b)
47         : instruction(a != 0 ? i : nullptr), a_constant(a), b_constant(b), is_known(true) {}
ValueValue48     explicit Value(int32_t b) : Value(nullptr, 0, b) {}
49     // Representation as: a_constant x instruction + b_constant.
50     HInstruction* instruction;
51     int32_t a_constant;
52     int32_t b_constant;
53     // If true, represented by prior fields. Otherwise unknown value.
54     bool is_known;
55   };
56 
57   explicit InductionVarRange(HInductionVarAnalysis* induction);
58 
59   /**
60    * Given a context denoted by the first instruction, returns a possibly conservative
61    * lower and upper bound on the instruction's value in the output parameters min_val
62    * and max_val, respectively. The need_finite_test flag denotes if an additional finite-test
63    * is needed to protect the range evaluation inside its loop. Returns false on failure.
64    */
65   bool GetInductionRange(HInstruction* context,
66                          HInstruction* instruction,
67                          /*out*/ Value* min_val,
68                          /*out*/ Value* max_val,
69                          /*out*/ bool* needs_finite_test);
70 
71   /** Refines the values with induction of next outer loop. Returns true on change. */
72   bool RefineOuter(/*in-out*/ Value* min_val,
73                    /*in-out*/ Value* max_val) const;
74 
75   /**
76    * Returns true if range analysis is able to generate code for the lower and upper
77    * bound expressions on the instruction in the given context. The need_finite_test
78    * and need_taken test flags denote if an additional finite-test and/or taken-test
79    * are needed to protect the range evaluation inside its loop.
80    */
81   bool CanGenerateCode(HInstruction* context,
82                        HInstruction* instruction,
83                        /*out*/ bool* needs_finite_test,
84                        /*out*/ bool* needs_taken_test);
85 
86   /**
87    * Generates the actual code in the HIR for the lower and upper bound expressions on the
88    * instruction in the given context. Code for the lower and upper bound expression are
89    * generated in given block and graph and are returned in the output parameters lower and
90    * upper, respectively. For a loop invariant, lower is not set.
91    *
92    * For example, given expression x+i with range [0, 5] for i, calling this method
93    * will generate the following sequence:
94    *
95    * block:
96    *   lower: add x, 0
97    *   upper: add x, 5
98    *
99    * Precondition: CanGenerateCode() returns true.
100    */
101   void GenerateRangeCode(HInstruction* context,
102                          HInstruction* instruction,
103                          HGraph* graph,
104                          HBasicBlock* block,
105                          /*out*/ HInstruction** lower,
106                          /*out*/ HInstruction** upper);
107 
108   /**
109    * Generates explicit taken-test for the loop in the given context. Code is generated in
110    * given block and graph. The taken-test is returned in parameter test.
111    *
112    * Precondition: CanGenerateCode() returns true and needs_taken_test is set.
113    */
114   void GenerateTakenTest(HInstruction* context,
115                          HGraph* graph,
116                          HBasicBlock* block,
117                          /*out*/ HInstruction** taken_test);
118 
119  private:
120   /*
121    * Enum used in IsConstant() request.
122    */
123   enum ConstantRequest {
124     kExact,
125     kAtMost,
126     kAtLeast
127   };
128 
129   /**
130    * Returns true if exact or upper/lower bound on the given induction
131    * information is known as a 64-bit constant, which is returned in value.
132    */
133   bool IsConstant(HInductionVarAnalysis::InductionInfo* info,
134                   ConstantRequest request,
135                   /*out*/ int64_t *value) const;
136 
137   bool NeedsTripCount(HInductionVarAnalysis::InductionInfo* info) const;
138   bool IsBodyTripCount(HInductionVarAnalysis::InductionInfo* trip) const;
139   bool IsUnsafeTripCount(HInductionVarAnalysis::InductionInfo* trip) const;
140 
141   Value GetLinear(HInductionVarAnalysis::InductionInfo* info,
142                   HInductionVarAnalysis::InductionInfo* trip,
143                   bool in_body,
144                   bool is_min) const;
145   Value GetFetch(HInstruction* instruction,
146                  HInductionVarAnalysis::InductionInfo* trip,
147                  bool in_body,
148                  bool is_min) const;
149   Value GetVal(HInductionVarAnalysis::InductionInfo* info,
150                HInductionVarAnalysis::InductionInfo* trip,
151                bool in_body,
152                bool is_min) const;
153   Value GetMul(HInductionVarAnalysis::InductionInfo* info1,
154                HInductionVarAnalysis::InductionInfo* info2,
155                HInductionVarAnalysis::InductionInfo* trip,
156                bool in_body,
157                bool is_min) const;
158   Value GetDiv(HInductionVarAnalysis::InductionInfo* info1,
159                HInductionVarAnalysis::InductionInfo* info2,
160                HInductionVarAnalysis::InductionInfo* trip,
161                bool in_body,
162                bool is_min) const;
163 
164   Value MulRangeAndConstant(Value v1, Value v2, Value c, bool is_min) const;
165   Value DivRangeAndConstant(Value v1, Value v2, Value c, bool is_min) const;
166 
167   Value AddValue(Value v1, Value v2) const;
168   Value SubValue(Value v1, Value v2) const;
169   Value MulValue(Value v1, Value v2) const;
170   Value DivValue(Value v1, Value v2) const;
171   Value MergeVal(Value v1, Value v2, bool is_min) const;
172 
173   /**
174    * Returns refined value using induction of next outer loop or the input value if no
175    * further refinement is possible.
176    */
177   Value RefineOuter(Value val, bool is_min) const;
178 
179   /**
180    * Generates code for lower/upper/taken-test in the HIR. Returns true on success.
181    * With values nullptr, the method can be used to determine if code generation
182    * would be successful without generating actual code yet.
183    */
184   bool GenerateCode(HInstruction* context,
185                     HInstruction* instruction,
186                     HGraph* graph,
187                     HBasicBlock* block,
188                     /*out*/ HInstruction** lower,
189                     /*out*/ HInstruction** upper,
190                     /*out*/ HInstruction** taken_test,
191                     /*out*/ bool* needs_finite_test,
192                     /*out*/ bool* needs_taken_test) const;
193 
194   bool GenerateCode(HInductionVarAnalysis::InductionInfo* info,
195                     HInductionVarAnalysis::InductionInfo* trip,
196                     HGraph* graph,
197                     HBasicBlock* block,
198                     /*out*/ HInstruction** result,
199                     bool in_body,
200                     bool is_min) const;
201 
202   /** Results of prior induction variable analysis. */
203   HInductionVarAnalysis *induction_analysis_;
204 
205   friend class HInductionVarAnalysis;
206   friend class InductionVarRangeTest;
207 
208   DISALLOW_COPY_AND_ASSIGN(InductionVarRange);
209 };
210 
211 }  // namespace art
212 
213 #endif  // ART_COMPILER_OPTIMIZING_INDUCTION_VAR_RANGE_H_
214