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 #include "optimization.h"
18
19 #ifdef ART_ENABLE_CODEGEN_arm
20 #include "instruction_simplifier_arm.h"
21 #endif
22 #ifdef ART_ENABLE_CODEGEN_arm64
23 #include "instruction_simplifier_arm64.h"
24 #endif
25 #ifdef ART_ENABLE_CODEGEN_x86
26 #include "pc_relative_fixups_x86.h"
27 #include "instruction_simplifier_x86.h"
28 #endif
29 #if defined(ART_ENABLE_CODEGEN_x86) || defined(ART_ENABLE_CODEGEN_x86_64)
30 #include "x86_memory_gen.h"
31 #endif
32 #ifdef ART_ENABLE_CODEGEN_x86_64
33 #include "instruction_simplifier_x86_64.h"
34 #endif
35
36 #include "bounds_check_elimination.h"
37 #include "cha_guard_optimization.h"
38 #include "code_sinking.h"
39 #include "constant_folding.h"
40 #include "constructor_fence_redundancy_elimination.h"
41 #include "dead_code_elimination.h"
42 #include "dex/code_item_accessors-inl.h"
43 #include "driver/compiler_options.h"
44 #include "driver/dex_compilation_unit.h"
45 #include "gvn.h"
46 #include "induction_var_analysis.h"
47 #include "inliner.h"
48 #include "instruction_simplifier.h"
49 #include "intrinsics.h"
50 #include "licm.h"
51 #include "load_store_analysis.h"
52 #include "load_store_elimination.h"
53 #include "loop_optimization.h"
54 #include "scheduler.h"
55 #include "select_generator.h"
56 #include "sharpening.h"
57 #include "side_effects_analysis.h"
58
59 // Decide between default or alternative pass name.
60
61 namespace art {
62
OptimizationPassName(OptimizationPass pass)63 const char* OptimizationPassName(OptimizationPass pass) {
64 switch (pass) {
65 case OptimizationPass::kSideEffectsAnalysis:
66 return SideEffectsAnalysis::kSideEffectsAnalysisPassName;
67 case OptimizationPass::kInductionVarAnalysis:
68 return HInductionVarAnalysis::kInductionPassName;
69 case OptimizationPass::kLoadStoreAnalysis:
70 return LoadStoreAnalysis::kLoadStoreAnalysisPassName;
71 case OptimizationPass::kGlobalValueNumbering:
72 return GVNOptimization::kGlobalValueNumberingPassName;
73 case OptimizationPass::kInvariantCodeMotion:
74 return LICM::kLoopInvariantCodeMotionPassName;
75 case OptimizationPass::kLoopOptimization:
76 return HLoopOptimization::kLoopOptimizationPassName;
77 case OptimizationPass::kBoundsCheckElimination:
78 return BoundsCheckElimination::kBoundsCheckEliminationPassName;
79 case OptimizationPass::kLoadStoreElimination:
80 return LoadStoreElimination::kLoadStoreEliminationPassName;
81 case OptimizationPass::kConstantFolding:
82 return HConstantFolding::kConstantFoldingPassName;
83 case OptimizationPass::kDeadCodeElimination:
84 return HDeadCodeElimination::kDeadCodeEliminationPassName;
85 case OptimizationPass::kInliner:
86 return HInliner::kInlinerPassName;
87 case OptimizationPass::kSelectGenerator:
88 return HSelectGenerator::kSelectGeneratorPassName;
89 case OptimizationPass::kInstructionSimplifier:
90 return InstructionSimplifier::kInstructionSimplifierPassName;
91 case OptimizationPass::kCHAGuardOptimization:
92 return CHAGuardOptimization::kCHAGuardOptimizationPassName;
93 case OptimizationPass::kCodeSinking:
94 return CodeSinking::kCodeSinkingPassName;
95 case OptimizationPass::kConstructorFenceRedundancyElimination:
96 return ConstructorFenceRedundancyElimination::kCFREPassName;
97 case OptimizationPass::kScheduling:
98 return HInstructionScheduling::kInstructionSchedulingPassName;
99 #ifdef ART_ENABLE_CODEGEN_arm
100 case OptimizationPass::kInstructionSimplifierArm:
101 return arm::InstructionSimplifierArm::kInstructionSimplifierArmPassName;
102 #endif
103 #ifdef ART_ENABLE_CODEGEN_arm64
104 case OptimizationPass::kInstructionSimplifierArm64:
105 return arm64::InstructionSimplifierArm64::kInstructionSimplifierArm64PassName;
106 #endif
107 #ifdef ART_ENABLE_CODEGEN_x86
108 case OptimizationPass::kPcRelativeFixupsX86:
109 return x86::PcRelativeFixups::kPcRelativeFixupsX86PassName;
110 case OptimizationPass::kInstructionSimplifierX86:
111 return x86::InstructionSimplifierX86::kInstructionSimplifierX86PassName;
112 #endif
113 #ifdef ART_ENABLE_CODEGEN_x86_64
114 case OptimizationPass::kInstructionSimplifierX86_64:
115 return x86_64::InstructionSimplifierX86_64::kInstructionSimplifierX86_64PassName;
116 #endif
117 #if defined(ART_ENABLE_CODEGEN_x86) || defined(ART_ENABLE_CODEGEN_x86_64)
118 case OptimizationPass::kX86MemoryOperandGeneration:
119 return x86::X86MemoryOperandGeneration::kX86MemoryOperandGenerationPassName;
120 #endif
121 case OptimizationPass::kNone:
122 LOG(FATAL) << "kNone does not represent an actual pass";
123 UNREACHABLE();
124 }
125 }
126
127 #define X(x) if (pass_name == OptimizationPassName((x))) return (x)
128
OptimizationPassByName(const std::string & pass_name)129 OptimizationPass OptimizationPassByName(const std::string& pass_name) {
130 X(OptimizationPass::kBoundsCheckElimination);
131 X(OptimizationPass::kCHAGuardOptimization);
132 X(OptimizationPass::kCodeSinking);
133 X(OptimizationPass::kConstantFolding);
134 X(OptimizationPass::kConstructorFenceRedundancyElimination);
135 X(OptimizationPass::kDeadCodeElimination);
136 X(OptimizationPass::kGlobalValueNumbering);
137 X(OptimizationPass::kInductionVarAnalysis);
138 X(OptimizationPass::kInliner);
139 X(OptimizationPass::kInstructionSimplifier);
140 X(OptimizationPass::kInvariantCodeMotion);
141 X(OptimizationPass::kLoadStoreAnalysis);
142 X(OptimizationPass::kLoadStoreElimination);
143 X(OptimizationPass::kLoopOptimization);
144 X(OptimizationPass::kScheduling);
145 X(OptimizationPass::kSelectGenerator);
146 X(OptimizationPass::kSideEffectsAnalysis);
147 #ifdef ART_ENABLE_CODEGEN_arm
148 X(OptimizationPass::kInstructionSimplifierArm);
149 #endif
150 #ifdef ART_ENABLE_CODEGEN_arm64
151 X(OptimizationPass::kInstructionSimplifierArm64);
152 #endif
153 #ifdef ART_ENABLE_CODEGEN_x86
154 X(OptimizationPass::kPcRelativeFixupsX86);
155 X(OptimizationPass::kX86MemoryOperandGeneration);
156 #endif
157 LOG(FATAL) << "Cannot find optimization " << pass_name;
158 UNREACHABLE();
159 }
160
161 #undef X
162
ConstructOptimizations(const OptimizationDef definitions[],size_t length,ArenaAllocator * allocator,HGraph * graph,OptimizingCompilerStats * stats,CodeGenerator * codegen,const DexCompilationUnit & dex_compilation_unit,VariableSizedHandleScope * handles)163 ArenaVector<HOptimization*> ConstructOptimizations(
164 const OptimizationDef definitions[],
165 size_t length,
166 ArenaAllocator* allocator,
167 HGraph* graph,
168 OptimizingCompilerStats* stats,
169 CodeGenerator* codegen,
170 const DexCompilationUnit& dex_compilation_unit,
171 VariableSizedHandleScope* handles) {
172 ArenaVector<HOptimization*> optimizations(allocator->Adapter());
173
174 // Some optimizations require SideEffectsAnalysis or HInductionVarAnalysis
175 // instances. This method uses the nearest instance preceeding it in the pass
176 // name list or fails fatally if no such analysis can be found.
177 SideEffectsAnalysis* most_recent_side_effects = nullptr;
178 HInductionVarAnalysis* most_recent_induction = nullptr;
179 LoadStoreAnalysis* most_recent_lsa = nullptr;
180
181 // Loop over the requested optimizations.
182 for (size_t i = 0; i < length; i++) {
183 OptimizationPass pass = definitions[i].pass;
184 const char* alt_name = definitions[i].pass_name;
185 const char* pass_name = alt_name != nullptr
186 ? alt_name
187 : OptimizationPassName(pass);
188 HOptimization* opt = nullptr;
189
190 switch (pass) {
191 //
192 // Analysis passes (kept in most recent for subsequent passes).
193 //
194 case OptimizationPass::kSideEffectsAnalysis:
195 opt = most_recent_side_effects = new (allocator) SideEffectsAnalysis(graph, pass_name);
196 break;
197 case OptimizationPass::kInductionVarAnalysis:
198 opt = most_recent_induction = new (allocator) HInductionVarAnalysis(graph, pass_name);
199 break;
200 case OptimizationPass::kLoadStoreAnalysis:
201 opt = most_recent_lsa = new (allocator) LoadStoreAnalysis(graph, pass_name);
202 break;
203 //
204 // Passes that need prior analysis.
205 //
206 case OptimizationPass::kGlobalValueNumbering:
207 CHECK(most_recent_side_effects != nullptr);
208 opt = new (allocator) GVNOptimization(graph, *most_recent_side_effects, pass_name);
209 break;
210 case OptimizationPass::kInvariantCodeMotion:
211 CHECK(most_recent_side_effects != nullptr);
212 opt = new (allocator) LICM(graph, *most_recent_side_effects, stats, pass_name);
213 break;
214 case OptimizationPass::kLoopOptimization:
215 CHECK(most_recent_induction != nullptr);
216 opt = new (allocator) HLoopOptimization(
217 graph, &codegen->GetCompilerOptions(), most_recent_induction, stats, pass_name);
218 break;
219 case OptimizationPass::kBoundsCheckElimination:
220 CHECK(most_recent_side_effects != nullptr && most_recent_induction != nullptr);
221 opt = new (allocator) BoundsCheckElimination(
222 graph, *most_recent_side_effects, most_recent_induction, pass_name);
223 break;
224 case OptimizationPass::kLoadStoreElimination:
225 CHECK(most_recent_side_effects != nullptr && most_recent_induction != nullptr);
226 opt = new (allocator) LoadStoreElimination(
227 graph, *most_recent_side_effects, *most_recent_lsa, stats, pass_name);
228 break;
229 //
230 // Regular passes.
231 //
232 case OptimizationPass::kConstantFolding:
233 opt = new (allocator) HConstantFolding(graph, pass_name);
234 break;
235 case OptimizationPass::kDeadCodeElimination:
236 opt = new (allocator) HDeadCodeElimination(graph, stats, pass_name);
237 break;
238 case OptimizationPass::kInliner: {
239 CodeItemDataAccessor accessor(*dex_compilation_unit.GetDexFile(),
240 dex_compilation_unit.GetCodeItem());
241 opt = new (allocator) HInliner(graph, // outer_graph
242 graph, // outermost_graph
243 codegen,
244 dex_compilation_unit, // outer_compilation_unit
245 dex_compilation_unit, // outermost_compilation_unit
246 handles,
247 stats,
248 accessor.RegistersSize(),
249 /* total_number_of_instructions= */ 0,
250 /* parent= */ nullptr,
251 /* depth= */ 0,
252 pass_name);
253 break;
254 }
255 case OptimizationPass::kSelectGenerator:
256 opt = new (allocator) HSelectGenerator(graph, handles, stats, pass_name);
257 break;
258 case OptimizationPass::kInstructionSimplifier:
259 opt = new (allocator) InstructionSimplifier(graph, codegen, stats, pass_name);
260 break;
261 case OptimizationPass::kCHAGuardOptimization:
262 opt = new (allocator) CHAGuardOptimization(graph, pass_name);
263 break;
264 case OptimizationPass::kCodeSinking:
265 opt = new (allocator) CodeSinking(graph, stats, pass_name);
266 break;
267 case OptimizationPass::kConstructorFenceRedundancyElimination:
268 opt = new (allocator) ConstructorFenceRedundancyElimination(graph, stats, pass_name);
269 break;
270 case OptimizationPass::kScheduling:
271 opt = new (allocator) HInstructionScheduling(
272 graph, codegen->GetCompilerOptions().GetInstructionSet(), codegen, pass_name);
273 break;
274 //
275 // Arch-specific passes.
276 //
277 #ifdef ART_ENABLE_CODEGEN_arm
278 case OptimizationPass::kInstructionSimplifierArm:
279 DCHECK(alt_name == nullptr) << "arch-specific pass does not support alternative name";
280 opt = new (allocator) arm::InstructionSimplifierArm(graph, stats);
281 break;
282 #endif
283 #ifdef ART_ENABLE_CODEGEN_arm64
284 case OptimizationPass::kInstructionSimplifierArm64:
285 DCHECK(alt_name == nullptr) << "arch-specific pass does not support alternative name";
286 opt = new (allocator) arm64::InstructionSimplifierArm64(graph, stats);
287 break;
288 #endif
289 #ifdef ART_ENABLE_CODEGEN_x86
290 case OptimizationPass::kPcRelativeFixupsX86:
291 DCHECK(alt_name == nullptr) << "arch-specific pass does not support alternative name";
292 opt = new (allocator) x86::PcRelativeFixups(graph, codegen, stats);
293 break;
294 case OptimizationPass::kX86MemoryOperandGeneration:
295 DCHECK(alt_name == nullptr) << "arch-specific pass does not support alternative name";
296 opt = new (allocator) x86::X86MemoryOperandGeneration(graph, codegen, stats);
297 break;
298 case OptimizationPass::kInstructionSimplifierX86:
299 opt = new (allocator) x86::InstructionSimplifierX86(graph, codegen, stats);
300 break;
301 #endif
302 #ifdef ART_ENABLE_CODEGEN_x86_64
303 case OptimizationPass::kInstructionSimplifierX86_64:
304 opt = new (allocator) x86_64::InstructionSimplifierX86_64(graph, codegen, stats);
305 break;
306 #endif
307 case OptimizationPass::kNone:
308 LOG(FATAL) << "kNone does not represent an actual pass";
309 UNREACHABLE();
310 } // switch
311
312 // Add each next optimization to result vector.
313 CHECK(opt != nullptr);
314 DCHECK_STREQ(pass_name, opt->GetPassName()); // sanity
315 optimizations.push_back(opt);
316 }
317
318 return optimizations;
319 }
320
321 } // namespace art
322