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