1 /*
2  * Copyright (C) 2014 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_DEX_BB_OPTIMIZATIONS_H_
18 #define ART_COMPILER_DEX_BB_OPTIMIZATIONS_H_
19 
20 #include "compiler_internals.h"
21 #include "pass_me.h"
22 
23 namespace art {
24 
25 /**
26  * @class CacheFieldLoweringInfo
27  * @brief Cache the lowering info for fields used by IGET/IPUT/SGET/SPUT insns.
28  */
29 class CacheFieldLoweringInfo : public PassME {
30  public:
CacheFieldLoweringInfo()31   CacheFieldLoweringInfo() : PassME("CacheFieldLoweringInfo", kNoNodes) {
32   }
33 
Start(PassDataHolder * data)34   void Start(PassDataHolder* data) const {
35     DCHECK(data != nullptr);
36     CompilationUnit* c_unit = down_cast<PassMEDataHolder*>(data)->c_unit;
37     DCHECK(c_unit != nullptr);
38     c_unit->mir_graph->DoCacheFieldLoweringInfo();
39   }
40 
Gate(const PassDataHolder * data)41   bool Gate(const PassDataHolder* data) const {
42     DCHECK(data != nullptr);
43     CompilationUnit* c_unit = down_cast<const PassMEDataHolder*>(data)->c_unit;
44     DCHECK(c_unit != nullptr);
45     return c_unit->mir_graph->HasFieldAccess();
46   }
47 };
48 
49 /**
50  * @class CacheMethodLoweringInfo
51  * @brief Cache the lowering info for methods called by INVOKEs.
52  */
53 class CacheMethodLoweringInfo : public PassME {
54  public:
CacheMethodLoweringInfo()55   CacheMethodLoweringInfo() : PassME("CacheMethodLoweringInfo", kNoNodes) {
56   }
57 
Start(PassDataHolder * data)58   void Start(PassDataHolder* data) const {
59     DCHECK(data != nullptr);
60     CompilationUnit* c_unit = down_cast<PassMEDataHolder*>(data)->c_unit;
61     DCHECK(c_unit != nullptr);
62     c_unit->mir_graph->DoCacheMethodLoweringInfo();
63   }
64 
Gate(const PassDataHolder * data)65   bool Gate(const PassDataHolder* data) const {
66     DCHECK(data != nullptr);
67     CompilationUnit* c_unit = down_cast<const PassMEDataHolder*>(data)->c_unit;
68     DCHECK(c_unit != nullptr);
69     return c_unit->mir_graph->HasInvokes();
70   }
71 };
72 
73 /**
74  * @class SpecialMethodInliner
75  * @brief Performs method inlining pass on special kinds of methods.
76  * @details Special methods are methods that fall in one of the following categories:
77  * empty, instance getter, instance setter, argument return, and constant return.
78  */
79 class SpecialMethodInliner : public PassME {
80  public:
SpecialMethodInliner()81   SpecialMethodInliner() : PassME("SpecialMethodInliner") {
82   }
83 
Gate(const PassDataHolder * data)84   bool Gate(const PassDataHolder* data) const {
85     DCHECK(data != nullptr);
86     CompilationUnit* c_unit = down_cast<const PassMEDataHolder*>(data)->c_unit;
87     DCHECK(c_unit != nullptr);
88     return c_unit->mir_graph->InlineSpecialMethodsGate();
89   }
90 
Start(PassDataHolder * data)91   void Start(PassDataHolder* data) const {
92     DCHECK(data != nullptr);
93     CompilationUnit* c_unit = down_cast<PassMEDataHolder*>(data)->c_unit;
94     DCHECK(c_unit != nullptr);
95     c_unit->mir_graph->InlineSpecialMethodsStart();
96   }
97 
Worker(const PassDataHolder * data)98   bool Worker(const PassDataHolder* data) const {
99     DCHECK(data != nullptr);
100     const PassMEDataHolder* pass_me_data_holder = down_cast<const PassMEDataHolder*>(data);
101     CompilationUnit* c_unit = pass_me_data_holder->c_unit;
102     DCHECK(c_unit != nullptr);
103     BasicBlock* bb = pass_me_data_holder->bb;
104     DCHECK(bb != nullptr);
105     c_unit->mir_graph->InlineSpecialMethods(bb);
106     // No need of repeating, so just return false.
107     return false;
108   }
109 
End(PassDataHolder * data)110   void End(PassDataHolder* data) const {
111     DCHECK(data != nullptr);
112     CompilationUnit* c_unit = down_cast<PassMEDataHolder*>(data)->c_unit;
113     DCHECK(c_unit != nullptr);
114     c_unit->mir_graph->InlineSpecialMethodsEnd();
115   }
116 };
117 
118 /**
119  * @class CodeLayout
120  * @brief Perform the code layout pass.
121  */
122 class CodeLayout : public PassME {
123  public:
CodeLayout()124   CodeLayout() : PassME("CodeLayout", kAllNodes, kOptimizationBasicBlockChange, "2_post_layout_cfg") {
125   }
126 
Start(PassDataHolder * data)127   void Start(PassDataHolder* data) const {
128     DCHECK(data != nullptr);
129     CompilationUnit* c_unit = down_cast<PassMEDataHolder*>(data)->c_unit;
130     DCHECK(c_unit != nullptr);
131     c_unit->mir_graph->VerifyDataflow();
132     c_unit->mir_graph->ClearAllVisitedFlags();
133   }
134 
135   bool Worker(const PassDataHolder* data) const;
136 };
137 
138 /**
139  * @class NullCheckEliminationAndTypeInference
140  * @brief Null check elimination and type inference.
141  */
142 class NullCheckEliminationAndTypeInference : public PassME {
143  public:
NullCheckEliminationAndTypeInference()144   NullCheckEliminationAndTypeInference()
145     : PassME("NCE_TypeInference", kRepeatingTopologicalSortTraversal, "4_post_nce_cfg") {
146   }
147 
Start(PassDataHolder * data)148   void Start(PassDataHolder* data) const {
149     DCHECK(data != nullptr);
150     CompilationUnit* c_unit = down_cast<PassMEDataHolder*>(data)->c_unit;
151     DCHECK(c_unit != nullptr);
152     c_unit->mir_graph->EliminateNullChecksAndInferTypesStart();
153   }
154 
Worker(const PassDataHolder * data)155   bool Worker(const PassDataHolder* data) const {
156     DCHECK(data != nullptr);
157     const PassMEDataHolder* pass_me_data_holder = down_cast<const PassMEDataHolder*>(data);
158     CompilationUnit* c_unit = pass_me_data_holder->c_unit;
159     DCHECK(c_unit != nullptr);
160     BasicBlock* bb = pass_me_data_holder->bb;
161     DCHECK(bb != nullptr);
162     return c_unit->mir_graph->EliminateNullChecksAndInferTypes(bb);
163   }
164 
End(PassDataHolder * data)165   void End(PassDataHolder* data) const {
166     DCHECK(data != nullptr);
167     CompilationUnit* c_unit = down_cast<PassMEDataHolder*>(data)->c_unit;
168     DCHECK(c_unit != nullptr);
169     c_unit->mir_graph->EliminateNullChecksAndInferTypesEnd();
170   }
171 };
172 
173 class ClassInitCheckElimination : public PassME {
174  public:
ClassInitCheckElimination()175   ClassInitCheckElimination()
176     : PassME("ClInitCheckElimination", kLoopRepeatingTopologicalSortTraversal) {
177   }
178 
Gate(const PassDataHolder * data)179   bool Gate(const PassDataHolder* data) const {
180     DCHECK(data != nullptr);
181     CompilationUnit* c_unit = down_cast<const PassMEDataHolder*>(data)->c_unit;
182     DCHECK(c_unit != nullptr);
183     return c_unit->mir_graph->EliminateClassInitChecksGate();
184   }
185 
Worker(const PassDataHolder * data)186   bool Worker(const PassDataHolder* data) const {
187     DCHECK(data != nullptr);
188     const PassMEDataHolder* pass_me_data_holder = down_cast<const PassMEDataHolder*>(data);
189     CompilationUnit* c_unit = pass_me_data_holder->c_unit;
190     DCHECK(c_unit != nullptr);
191     BasicBlock* bb = pass_me_data_holder->bb;
192     DCHECK(bb != nullptr);
193     return c_unit->mir_graph->EliminateClassInitChecks(bb);
194   }
195 
End(PassDataHolder * data)196   void End(PassDataHolder* data) const {
197     DCHECK(data != nullptr);
198     CompilationUnit* c_unit = down_cast<PassMEDataHolder*>(data)->c_unit;
199     DCHECK(c_unit != nullptr);
200     c_unit->mir_graph->EliminateClassInitChecksEnd();
201   }
202 };
203 
204 /**
205  * @class GlobalValueNumberingPass
206  * @brief Performs the global value numbering pass.
207  */
208 class GlobalValueNumberingPass : public PassME {
209  public:
GlobalValueNumberingPass()210   GlobalValueNumberingPass()
211     : PassME("GVN", kLoopRepeatingTopologicalSortTraversal, "4_post_gvn_cfg") {
212   }
213 
Gate(const PassDataHolder * data)214   bool Gate(const PassDataHolder* data) const OVERRIDE {
215     DCHECK(data != nullptr);
216     CompilationUnit* c_unit = down_cast<const PassMEDataHolder*>(data)->c_unit;
217     DCHECK(c_unit != nullptr);
218     return c_unit->mir_graph->ApplyGlobalValueNumberingGate();
219   }
220 
Worker(const PassDataHolder * data)221   bool Worker(const PassDataHolder* data) const OVERRIDE {
222     DCHECK(data != nullptr);
223     const PassMEDataHolder* pass_me_data_holder = down_cast<const PassMEDataHolder*>(data);
224     CompilationUnit* c_unit = pass_me_data_holder->c_unit;
225     DCHECK(c_unit != nullptr);
226     BasicBlock* bb = pass_me_data_holder->bb;
227     DCHECK(bb != nullptr);
228     return c_unit->mir_graph->ApplyGlobalValueNumbering(bb);
229   }
230 
End(PassDataHolder * data)231   void End(PassDataHolder* data) const OVERRIDE {
232     DCHECK(data != nullptr);
233     CompilationUnit* c_unit = down_cast<PassMEDataHolder*>(data)->c_unit;
234     DCHECK(c_unit != nullptr);
235     c_unit->mir_graph->ApplyGlobalValueNumberingEnd();
236   }
237 };
238 
239 /**
240  * @class BBCombine
241  * @brief Perform the basic block combination pass.
242  */
243 class BBCombine : public PassME {
244  public:
BBCombine()245   BBCombine() : PassME("BBCombine", kPreOrderDFSTraversal, "5_post_bbcombine_cfg") {
246   }
247 
Gate(const PassDataHolder * data)248   bool Gate(const PassDataHolder* data) const {
249     DCHECK(data != nullptr);
250     CompilationUnit* c_unit = down_cast<const PassMEDataHolder*>(data)->c_unit;
251     DCHECK(c_unit != nullptr);
252     return ((c_unit->disable_opt & (1 << kSuppressExceptionEdges)) != 0);
253   }
254 
255   bool Worker(const PassDataHolder* data) const;
256 };
257 
258 /**
259  * @class BasicBlock Optimizations
260  * @brief Any simple BasicBlock optimization can be put here.
261  */
262 class BBOptimizations : public PassME {
263  public:
BBOptimizations()264   BBOptimizations() : PassME("BBOptimizations", kNoNodes, "5_post_bbo_cfg") {
265   }
266 
Gate(const PassDataHolder * data)267   bool Gate(const PassDataHolder* data) const {
268     DCHECK(data != nullptr);
269     CompilationUnit* c_unit = down_cast<const PassMEDataHolder*>(data)->c_unit;
270     DCHECK(c_unit != nullptr);
271     return ((c_unit->disable_opt & (1 << kBBOpt)) == 0);
272   }
273 
274   void Start(PassDataHolder* data) const;
275 };
276 
277 }  // namespace art
278 
279 #endif  // ART_COMPILER_DEX_BB_OPTIMIZATIONS_H_
280