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