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_mips
26 #include "instruction_simplifier_mips.h"
27 #include "pc_relative_fixups_mips.h"
28 #endif
29 #ifdef ART_ENABLE_CODEGEN_x86
30 #include "pc_relative_fixups_x86.h"
31 #endif
32 #if defined(ART_ENABLE_CODEGEN_x86) || defined(ART_ENABLE_CODEGEN_x86_64)
33 #include "x86_memory_gen.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/dex_compilation_unit.h"
44 #include "gvn.h"
45 #include "induction_var_analysis.h"
46 #include "inliner.h"
47 #include "instruction_simplifier.h"
48 #include "intrinsics.h"
49 #include "licm.h"
50 #include "load_store_analysis.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::kLoadStoreAnalysis:
69       return LoadStoreAnalysis::kLoadStoreAnalysisPassName;
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::kConstantFolding:
81       return HConstantFolding::kConstantFoldingPassName;
82     case OptimizationPass::kDeadCodeElimination:
83       return HDeadCodeElimination::kDeadCodeEliminationPassName;
84     case OptimizationPass::kInliner:
85       return HInliner::kInlinerPassName;
86     case OptimizationPass::kSharpening:
87       return HSharpening::kSharpeningPassName;
88     case OptimizationPass::kSelectGenerator:
89       return HSelectGenerator::kSelectGeneratorPassName;
90     case OptimizationPass::kInstructionSimplifier:
91       return InstructionSimplifier::kInstructionSimplifierPassName;
92     case OptimizationPass::kIntrinsicsRecognizer:
93       return IntrinsicsRecognizer::kIntrinsicsRecognizerPassName;
94     case OptimizationPass::kCHAGuardOptimization:
95       return CHAGuardOptimization::kCHAGuardOptimizationPassName;
96     case OptimizationPass::kCodeSinking:
97       return CodeSinking::kCodeSinkingPassName;
98     case OptimizationPass::kConstructorFenceRedundancyElimination:
99       return ConstructorFenceRedundancyElimination::kCFREPassName;
100     case OptimizationPass::kScheduling:
101       return HInstructionScheduling::kInstructionSchedulingPassName;
102 #ifdef ART_ENABLE_CODEGEN_arm
103     case OptimizationPass::kInstructionSimplifierArm:
104       return arm::InstructionSimplifierArm::kInstructionSimplifierArmPassName;
105 #endif
106 #ifdef ART_ENABLE_CODEGEN_arm64
107     case OptimizationPass::kInstructionSimplifierArm64:
108       return arm64::InstructionSimplifierArm64::kInstructionSimplifierArm64PassName;
109 #endif
110 #ifdef ART_ENABLE_CODEGEN_mips
111     case OptimizationPass::kPcRelativeFixupsMips:
112       return mips::PcRelativeFixups::kPcRelativeFixupsMipsPassName;
113     case OptimizationPass::kInstructionSimplifierMips:
114       return mips::InstructionSimplifierMips::kInstructionSimplifierMipsPassName;
115 #endif
116 #ifdef ART_ENABLE_CODEGEN_x86
117     case OptimizationPass::kPcRelativeFixupsX86:
118       return x86::PcRelativeFixups::kPcRelativeFixupsX86PassName;
119 #endif
120 #if defined(ART_ENABLE_CODEGEN_x86) || defined(ART_ENABLE_CODEGEN_x86_64)
121     case OptimizationPass::kX86MemoryOperandGeneration:
122       return x86::X86MemoryOperandGeneration::kX86MemoryOperandGenerationPassName;
123 #endif
124   }
125 }
126 
127 #define X(x) if (name == OptimizationPassName((x))) return (x)
128 
OptimizationPassByName(const std::string & name)129 OptimizationPass OptimizationPassByName(const std::string& 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::kIntrinsicsRecognizer);
141   X(OptimizationPass::kInvariantCodeMotion);
142   X(OptimizationPass::kLoadStoreAnalysis);
143   X(OptimizationPass::kLoadStoreElimination);
144   X(OptimizationPass::kLoopOptimization);
145   X(OptimizationPass::kScheduling);
146   X(OptimizationPass::kSelectGenerator);
147   X(OptimizationPass::kSharpening);
148   X(OptimizationPass::kSideEffectsAnalysis);
149 #ifdef ART_ENABLE_CODEGEN_arm
150   X(OptimizationPass::kInstructionSimplifierArm);
151 #endif
152 #ifdef ART_ENABLE_CODEGEN_arm64
153   X(OptimizationPass::kInstructionSimplifierArm64);
154 #endif
155 #ifdef ART_ENABLE_CODEGEN_mips
156   X(OptimizationPass::kPcRelativeFixupsMips);
157   X(OptimizationPass::kInstructionSimplifierMips);
158 #endif
159 #ifdef ART_ENABLE_CODEGEN_x86
160   X(OptimizationPass::kPcRelativeFixupsX86);
161   X(OptimizationPass::kX86MemoryOperandGeneration);
162 #endif
163   LOG(FATAL) << "Cannot find optimization " << name;
164   UNREACHABLE();
165 }
166 
167 #undef X
168 
ConstructOptimizations(const OptimizationDef definitions[],size_t length,ArenaAllocator * allocator,HGraph * graph,OptimizingCompilerStats * stats,CodeGenerator * codegen,CompilerDriver * driver,const DexCompilationUnit & dex_compilation_unit,VariableSizedHandleScope * handles)169 ArenaVector<HOptimization*> ConstructOptimizations(
170     const OptimizationDef definitions[],
171     size_t length,
172     ArenaAllocator* allocator,
173     HGraph* graph,
174     OptimizingCompilerStats* stats,
175     CodeGenerator* codegen,
176     CompilerDriver* driver,
177     const DexCompilationUnit& dex_compilation_unit,
178     VariableSizedHandleScope* handles) {
179   ArenaVector<HOptimization*> optimizations(allocator->Adapter());
180 
181   // Some optimizations require SideEffectsAnalysis or HInductionVarAnalysis
182   // instances. This method uses the nearest instance preceeding it in the pass
183   // name list or fails fatally if no such analysis can be found.
184   SideEffectsAnalysis* most_recent_side_effects = nullptr;
185   HInductionVarAnalysis* most_recent_induction = nullptr;
186   LoadStoreAnalysis* most_recent_lsa = nullptr;
187 
188   // Loop over the requested optimizations.
189   for (size_t i = 0; i < length; i++) {
190     OptimizationPass pass = definitions[i].first;
191     const char* alt_name = definitions[i].second;
192     const char* name = alt_name != nullptr
193         ? alt_name
194         : OptimizationPassName(pass);
195     HOptimization* opt = nullptr;
196 
197     switch (pass) {
198       //
199       // Analysis passes (kept in most recent for subsequent passes).
200       //
201       case OptimizationPass::kSideEffectsAnalysis:
202         opt = most_recent_side_effects = new (allocator) SideEffectsAnalysis(graph, name);
203         break;
204       case OptimizationPass::kInductionVarAnalysis:
205         opt = most_recent_induction = new (allocator) HInductionVarAnalysis(graph, name);
206         break;
207       case OptimizationPass::kLoadStoreAnalysis:
208         opt = most_recent_lsa = new (allocator) LoadStoreAnalysis(graph, name);
209         break;
210       //
211       // Passes that need prior analysis.
212       //
213       case OptimizationPass::kGlobalValueNumbering:
214         CHECK(most_recent_side_effects != nullptr);
215         opt = new (allocator) GVNOptimization(graph, *most_recent_side_effects, name);
216         break;
217       case OptimizationPass::kInvariantCodeMotion:
218         CHECK(most_recent_side_effects != nullptr);
219         opt = new (allocator) LICM(graph, *most_recent_side_effects, stats, name);
220         break;
221       case OptimizationPass::kLoopOptimization:
222         CHECK(most_recent_induction != nullptr);
223         opt = new (allocator) HLoopOptimization(graph, driver, most_recent_induction, stats, name);
224         break;
225       case OptimizationPass::kBoundsCheckElimination:
226         CHECK(most_recent_side_effects != nullptr && most_recent_induction != nullptr);
227         opt = new (allocator) BoundsCheckElimination(
228             graph, *most_recent_side_effects, most_recent_induction, name);
229         break;
230       case OptimizationPass::kLoadStoreElimination:
231         CHECK(most_recent_side_effects != nullptr && most_recent_induction != nullptr);
232         opt = new (allocator) LoadStoreElimination(
233             graph, *most_recent_side_effects, *most_recent_lsa, stats, name);
234         break;
235       //
236       // Regular passes.
237       //
238       case OptimizationPass::kConstantFolding:
239         opt = new (allocator) HConstantFolding(graph, name);
240         break;
241       case OptimizationPass::kDeadCodeElimination:
242         opt = new (allocator) HDeadCodeElimination(graph, stats, name);
243         break;
244       case OptimizationPass::kInliner: {
245         CodeItemDataAccessor accessor(*dex_compilation_unit.GetDexFile(),
246                                       dex_compilation_unit.GetCodeItem());
247         opt = new (allocator) HInliner(graph,                   // outer_graph
248                                        graph,                   // outermost_graph
249                                        codegen,
250                                        dex_compilation_unit,    // outer_compilation_unit
251                                        dex_compilation_unit,    // outermost_compilation_unit
252                                        driver,
253                                        handles,
254                                        stats,
255                                        accessor.RegistersSize(),
256                                        /* total_number_of_instructions */ 0,
257                                        /* parent */ nullptr,
258                                        /* depth */ 0,
259                                        name);
260         break;
261       }
262       case OptimizationPass::kSharpening:
263         opt = new (allocator) HSharpening(graph, codegen, driver, name);
264         break;
265       case OptimizationPass::kSelectGenerator:
266         opt = new (allocator) HSelectGenerator(graph, handles, stats, name);
267         break;
268       case OptimizationPass::kInstructionSimplifier:
269         opt = new (allocator) InstructionSimplifier(graph, codegen, driver, stats, name);
270         break;
271       case OptimizationPass::kIntrinsicsRecognizer:
272         opt = new (allocator) IntrinsicsRecognizer(graph, stats, name);
273         break;
274       case OptimizationPass::kCHAGuardOptimization:
275         opt = new (allocator) CHAGuardOptimization(graph, name);
276         break;
277       case OptimizationPass::kCodeSinking:
278         opt = new (allocator) CodeSinking(graph, stats, name);
279         break;
280       case OptimizationPass::kConstructorFenceRedundancyElimination:
281         opt = new (allocator) ConstructorFenceRedundancyElimination(graph, stats, name);
282         break;
283       case OptimizationPass::kScheduling:
284         opt = new (allocator) HInstructionScheduling(
285             graph, driver->GetInstructionSet(), codegen, 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 #endif
296 #ifdef ART_ENABLE_CODEGEN_arm64
297       case OptimizationPass::kInstructionSimplifierArm64:
298         DCHECK(alt_name == nullptr) << "arch-specific pass does not support alternative name";
299         opt = new (allocator) arm64::InstructionSimplifierArm64(graph, stats);
300         break;
301 #endif
302 #ifdef ART_ENABLE_CODEGEN_mips
303       case OptimizationPass::kPcRelativeFixupsMips:
304         DCHECK(alt_name == nullptr) << "arch-specific pass does not support alternative name";
305         opt = new (allocator) mips::PcRelativeFixups(graph, codegen, stats);
306         break;
307       case OptimizationPass::kInstructionSimplifierMips:
308         DCHECK(alt_name == nullptr) << "arch-specific pass does not support alternative name";
309         opt = new (allocator) mips::InstructionSimplifierMips(graph, codegen, stats);
310         break;
311 #endif
312 #ifdef ART_ENABLE_CODEGEN_x86
313       case OptimizationPass::kPcRelativeFixupsX86:
314         DCHECK(alt_name == nullptr) << "arch-specific pass does not support alternative name";
315         opt = new (allocator) x86::PcRelativeFixups(graph, codegen, stats);
316         break;
317       case OptimizationPass::kX86MemoryOperandGeneration:
318         DCHECK(alt_name == nullptr) << "arch-specific pass does not support alternative name";
319         opt = new (allocator) x86::X86MemoryOperandGeneration(graph, codegen, stats);
320         break;
321 #endif
322     }  // switch
323 
324     // Add each next optimization to result vector.
325     CHECK(opt != nullptr);
326     DCHECK_STREQ(name, opt->GetPassName());  // sanity
327     optimizations.push_back(opt);
328   }
329 
330   return optimizations;
331 }
332 
333 }  // namespace art
334