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