/* * Copyright (C) 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "optimization.h" #ifdef ART_ENABLE_CODEGEN_arm #include "critical_native_abi_fixup_arm.h" #include "instruction_simplifier_arm.h" #endif #ifdef ART_ENABLE_CODEGEN_arm64 #include "instruction_simplifier_arm64.h" #endif #ifdef ART_ENABLE_CODEGEN_x86 #include "pc_relative_fixups_x86.h" #include "instruction_simplifier_x86.h" #endif #if defined(ART_ENABLE_CODEGEN_x86) || defined(ART_ENABLE_CODEGEN_x86_64) #include "x86_memory_gen.h" #endif #ifdef ART_ENABLE_CODEGEN_x86_64 #include "instruction_simplifier_x86_64.h" #endif #include "bounds_check_elimination.h" #include "cha_guard_optimization.h" #include "code_sinking.h" #include "constant_folding.h" #include "constructor_fence_redundancy_elimination.h" #include "dead_code_elimination.h" #include "dex/code_item_accessors-inl.h" #include "driver/compiler_options.h" #include "driver/dex_compilation_unit.h" #include "gvn.h" #include "induction_var_analysis.h" #include "inliner.h" #include "instruction_simplifier.h" #include "intrinsics.h" #include "licm.h" #include "load_store_elimination.h" #include "loop_optimization.h" #include "scheduler.h" #include "select_generator.h" #include "sharpening.h" #include "side_effects_analysis.h" // Decide between default or alternative pass name. namespace art { const char* OptimizationPassName(OptimizationPass pass) { switch (pass) { case OptimizationPass::kSideEffectsAnalysis: return SideEffectsAnalysis::kSideEffectsAnalysisPassName; case OptimizationPass::kInductionVarAnalysis: return HInductionVarAnalysis::kInductionPassName; case OptimizationPass::kGlobalValueNumbering: return GVNOptimization::kGlobalValueNumberingPassName; case OptimizationPass::kInvariantCodeMotion: return LICM::kLoopInvariantCodeMotionPassName; case OptimizationPass::kLoopOptimization: return HLoopOptimization::kLoopOptimizationPassName; case OptimizationPass::kBoundsCheckElimination: return BoundsCheckElimination::kBoundsCheckEliminationPassName; case OptimizationPass::kLoadStoreElimination: return LoadStoreElimination::kLoadStoreEliminationPassName; case OptimizationPass::kConstantFolding: return HConstantFolding::kConstantFoldingPassName; case OptimizationPass::kDeadCodeElimination: return HDeadCodeElimination::kDeadCodeEliminationPassName; case OptimizationPass::kInliner: return HInliner::kInlinerPassName; case OptimizationPass::kSelectGenerator: return HSelectGenerator::kSelectGeneratorPassName; case OptimizationPass::kAggressiveInstructionSimplifier: case OptimizationPass::kInstructionSimplifier: return InstructionSimplifier::kInstructionSimplifierPassName; case OptimizationPass::kCHAGuardOptimization: return CHAGuardOptimization::kCHAGuardOptimizationPassName; case OptimizationPass::kCodeSinking: return CodeSinking::kCodeSinkingPassName; case OptimizationPass::kConstructorFenceRedundancyElimination: return ConstructorFenceRedundancyElimination::kCFREPassName; case OptimizationPass::kScheduling: return HInstructionScheduling::kInstructionSchedulingPassName; #ifdef ART_ENABLE_CODEGEN_arm case OptimizationPass::kInstructionSimplifierArm: return arm::InstructionSimplifierArm::kInstructionSimplifierArmPassName; case OptimizationPass::kCriticalNativeAbiFixupArm: return arm::CriticalNativeAbiFixupArm::kCriticalNativeAbiFixupArmPassName; #endif #ifdef ART_ENABLE_CODEGEN_arm64 case OptimizationPass::kInstructionSimplifierArm64: return arm64::InstructionSimplifierArm64::kInstructionSimplifierArm64PassName; #endif #ifdef ART_ENABLE_CODEGEN_x86 case OptimizationPass::kPcRelativeFixupsX86: return x86::PcRelativeFixups::kPcRelativeFixupsX86PassName; case OptimizationPass::kInstructionSimplifierX86: return x86::InstructionSimplifierX86::kInstructionSimplifierX86PassName; #endif #ifdef ART_ENABLE_CODEGEN_x86_64 case OptimizationPass::kInstructionSimplifierX86_64: return x86_64::InstructionSimplifierX86_64::kInstructionSimplifierX86_64PassName; #endif #if defined(ART_ENABLE_CODEGEN_x86) || defined(ART_ENABLE_CODEGEN_x86_64) case OptimizationPass::kX86MemoryOperandGeneration: return x86::X86MemoryOperandGeneration::kX86MemoryOperandGenerationPassName; #endif case OptimizationPass::kNone: LOG(FATAL) << "kNone does not represent an actual pass"; UNREACHABLE(); } } #define X(x) if (pass_name == OptimizationPassName((x))) return (x) OptimizationPass OptimizationPassByName(const std::string& pass_name) { X(OptimizationPass::kBoundsCheckElimination); X(OptimizationPass::kCHAGuardOptimization); X(OptimizationPass::kCodeSinking); X(OptimizationPass::kConstantFolding); X(OptimizationPass::kConstructorFenceRedundancyElimination); X(OptimizationPass::kDeadCodeElimination); X(OptimizationPass::kGlobalValueNumbering); X(OptimizationPass::kInductionVarAnalysis); X(OptimizationPass::kInliner); X(OptimizationPass::kInstructionSimplifier); X(OptimizationPass::kInvariantCodeMotion); X(OptimizationPass::kLoadStoreElimination); X(OptimizationPass::kLoopOptimization); X(OptimizationPass::kScheduling); X(OptimizationPass::kSelectGenerator); X(OptimizationPass::kSideEffectsAnalysis); #ifdef ART_ENABLE_CODEGEN_arm X(OptimizationPass::kInstructionSimplifierArm); X(OptimizationPass::kCriticalNativeAbiFixupArm); #endif #ifdef ART_ENABLE_CODEGEN_arm64 X(OptimizationPass::kInstructionSimplifierArm64); #endif #ifdef ART_ENABLE_CODEGEN_x86 X(OptimizationPass::kPcRelativeFixupsX86); X(OptimizationPass::kX86MemoryOperandGeneration); #endif LOG(FATAL) << "Cannot find optimization " << pass_name; UNREACHABLE(); } #undef X ArenaVector ConstructOptimizations( const OptimizationDef definitions[], size_t length, ArenaAllocator* allocator, HGraph* graph, OptimizingCompilerStats* stats, CodeGenerator* codegen, const DexCompilationUnit& dex_compilation_unit) { ArenaVector optimizations(allocator->Adapter()); // Some optimizations require SideEffectsAnalysis or HInductionVarAnalysis // instances. This method uses the nearest instance preceeding it in the pass // name list or fails fatally if no such analysis can be found. SideEffectsAnalysis* most_recent_side_effects = nullptr; HInductionVarAnalysis* most_recent_induction = nullptr; // Loop over the requested optimizations. for (size_t i = 0; i < length; i++) { OptimizationPass pass = definitions[i].pass; const char* alt_name = definitions[i].pass_name; const char* pass_name = alt_name != nullptr ? alt_name : OptimizationPassName(pass); HOptimization* opt = nullptr; switch (pass) { // // Analysis passes (kept in most recent for subsequent passes). // case OptimizationPass::kSideEffectsAnalysis: opt = most_recent_side_effects = new (allocator) SideEffectsAnalysis(graph, pass_name); break; case OptimizationPass::kInductionVarAnalysis: opt = most_recent_induction = new (allocator) HInductionVarAnalysis(graph, pass_name); break; // // Passes that need prior analysis. // case OptimizationPass::kGlobalValueNumbering: CHECK(most_recent_side_effects != nullptr); opt = new (allocator) GVNOptimization(graph, *most_recent_side_effects, pass_name); break; case OptimizationPass::kInvariantCodeMotion: CHECK(most_recent_side_effects != nullptr); opt = new (allocator) LICM(graph, *most_recent_side_effects, stats, pass_name); break; case OptimizationPass::kLoopOptimization: CHECK(most_recent_induction != nullptr); opt = new (allocator) HLoopOptimization( graph, *codegen, most_recent_induction, stats, pass_name); break; case OptimizationPass::kBoundsCheckElimination: CHECK(most_recent_side_effects != nullptr && most_recent_induction != nullptr); opt = new (allocator) BoundsCheckElimination( graph, *most_recent_side_effects, most_recent_induction, pass_name); break; // // Regular passes. // case OptimizationPass::kConstantFolding: opt = new (allocator) HConstantFolding(graph, pass_name); break; case OptimizationPass::kDeadCodeElimination: opt = new (allocator) HDeadCodeElimination(graph, stats, pass_name); break; case OptimizationPass::kInliner: { CodeItemDataAccessor accessor(*dex_compilation_unit.GetDexFile(), dex_compilation_unit.GetCodeItem()); opt = new (allocator) HInliner(graph, // outer_graph graph, // outermost_graph codegen, dex_compilation_unit, // outer_compilation_unit dex_compilation_unit, // outermost_compilation_unit stats, accessor.RegistersSize(), /* total_number_of_instructions= */ 0, /* parent= */ nullptr, /* depth= */ 0, pass_name); break; } case OptimizationPass::kSelectGenerator: opt = new (allocator) HSelectGenerator(graph, stats, pass_name); break; case OptimizationPass::kInstructionSimplifier: opt = new (allocator) InstructionSimplifier(graph, codegen, stats, pass_name); break; case OptimizationPass::kAggressiveInstructionSimplifier: opt = new (allocator) InstructionSimplifier(graph, codegen, stats, pass_name, /* use_all_optimizations_ = */ true); break; case OptimizationPass::kCHAGuardOptimization: opt = new (allocator) CHAGuardOptimization(graph, pass_name); break; case OptimizationPass::kCodeSinking: opt = new (allocator) CodeSinking(graph, stats, pass_name); break; case OptimizationPass::kConstructorFenceRedundancyElimination: opt = new (allocator) ConstructorFenceRedundancyElimination(graph, stats, pass_name); break; case OptimizationPass::kLoadStoreElimination: opt = new (allocator) LoadStoreElimination(graph, stats, pass_name); break; case OptimizationPass::kScheduling: opt = new (allocator) HInstructionScheduling( graph, codegen->GetCompilerOptions().GetInstructionSet(), codegen, pass_name); break; // // Arch-specific passes. // #ifdef ART_ENABLE_CODEGEN_arm case OptimizationPass::kInstructionSimplifierArm: DCHECK(alt_name == nullptr) << "arch-specific pass does not support alternative name"; opt = new (allocator) arm::InstructionSimplifierArm(graph, stats); break; case OptimizationPass::kCriticalNativeAbiFixupArm: DCHECK(alt_name == nullptr) << "arch-specific pass does not support alternative name"; opt = new (allocator) arm::CriticalNativeAbiFixupArm(graph, stats); break; #endif #ifdef ART_ENABLE_CODEGEN_arm64 case OptimizationPass::kInstructionSimplifierArm64: DCHECK(alt_name == nullptr) << "arch-specific pass does not support alternative name"; opt = new (allocator) arm64::InstructionSimplifierArm64(graph, stats); break; #endif #ifdef ART_ENABLE_CODEGEN_x86 case OptimizationPass::kPcRelativeFixupsX86: DCHECK(alt_name == nullptr) << "arch-specific pass does not support alternative name"; opt = new (allocator) x86::PcRelativeFixups(graph, codegen, stats); break; case OptimizationPass::kX86MemoryOperandGeneration: DCHECK(alt_name == nullptr) << "arch-specific pass does not support alternative name"; opt = new (allocator) x86::X86MemoryOperandGeneration(graph, codegen, stats); break; case OptimizationPass::kInstructionSimplifierX86: opt = new (allocator) x86::InstructionSimplifierX86(graph, codegen, stats); break; #endif #ifdef ART_ENABLE_CODEGEN_x86_64 case OptimizationPass::kInstructionSimplifierX86_64: opt = new (allocator) x86_64::InstructionSimplifierX86_64(graph, codegen, stats); break; #endif case OptimizationPass::kNone: LOG(FATAL) << "kNone does not represent an actual pass"; UNREACHABLE(); } // switch // Add each next optimization to result vector. CHECK(opt != nullptr); DCHECK_STREQ(pass_name, opt->GetPassName()); // Consistency check. optimizations.push_back(opt); } return optimizations; } } // namespace art