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