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