diff options
Diffstat (limited to 'compiler/dex/frontend.cc')
-rw-r--r-- | compiler/dex/frontend.cc | 292 |
1 files changed, 292 insertions, 0 deletions
diff --git a/compiler/dex/frontend.cc b/compiler/dex/frontend.cc new file mode 100644 index 000000000..746d475a9 --- /dev/null +++ b/compiler/dex/frontend.cc @@ -0,0 +1,292 @@ +/* + * Copyright (C) 2011 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 <llvm/Support/Threading.h> + +#include "compiler_internals.h" +#include "driver/compiler_driver.h" +#include "dataflow_iterator-inl.h" +#include "leb128.h" +#include "mirror/object.h" +#include "runtime.h" +#include "backend.h" +#include "base/logging.h" + +#if defined(ART_USE_PORTABLE_COMPILER) +#include "dex/portable/mir_to_gbc.h" +#include "llvm/llvm_compilation_unit.h" +#endif + +namespace { +#if !defined(ART_USE_PORTABLE_COMPILER) + pthread_once_t llvm_multi_init = PTHREAD_ONCE_INIT; +#endif + void InitializeLLVMForQuick() { + ::llvm::llvm_start_multithreaded(); + } +} + +namespace art { +namespace llvm { +::llvm::Module* makeLLVMModuleContents(::llvm::Module* module); +} + +LLVMInfo::LLVMInfo() { +#if !defined(ART_USE_PORTABLE_COMPILER) + pthread_once(&llvm_multi_init, InitializeLLVMForQuick); +#endif + // Create context, module, intrinsic helper & ir builder + llvm_context_.reset(new ::llvm::LLVMContext()); + llvm_module_ = new ::llvm::Module("art", *llvm_context_); + ::llvm::StructType::create(*llvm_context_, "JavaObject"); + art::llvm::makeLLVMModuleContents(llvm_module_); + intrinsic_helper_.reset( new art::llvm::IntrinsicHelper(*llvm_context_, *llvm_module_)); + ir_builder_.reset(new art::llvm::IRBuilder(*llvm_context_, *llvm_module_, *intrinsic_helper_)); +} + +LLVMInfo::~LLVMInfo() { +} + +extern "C" void ArtInitQuickCompilerContext(art::CompilerDriver& compiler) { + CHECK(compiler.GetCompilerContext() == NULL); + LLVMInfo* llvm_info = new LLVMInfo(); + compiler.SetCompilerContext(llvm_info); +} + +extern "C" void ArtUnInitQuickCompilerContext(art::CompilerDriver& compiler) { + delete reinterpret_cast<LLVMInfo*>(compiler.GetCompilerContext()); + compiler.SetCompilerContext(NULL); +} + +/* Default optimizer/debug setting for the compiler. */ +static uint32_t kCompilerOptimizerDisableFlags = 0 | // Disable specific optimizations + (1 << kLoadStoreElimination) | + //(1 << kLoadHoisting) | + //(1 << kSuppressLoads) | + //(1 << kNullCheckElimination) | + //(1 << kPromoteRegs) | + //(1 << kTrackLiveTemps) | + //(1 << kSafeOptimizations) | + //(1 << kBBOpt) | + //(1 << kMatch) | + //(1 << kPromoteCompilerTemps) | + 0; + +static uint32_t kCompilerDebugFlags = 0 | // Enable debug/testing modes + //(1 << kDebugDisplayMissingTargets) | + //(1 << kDebugVerbose) | + //(1 << kDebugDumpCFG) | + //(1 << kDebugSlowFieldPath) | + //(1 << kDebugSlowInvokePath) | + //(1 << kDebugSlowStringPath) | + //(1 << kDebugSlowestFieldPath) | + //(1 << kDebugSlowestStringPath) | + //(1 << kDebugExerciseResolveMethod) | + //(1 << kDebugVerifyDataflow) | + //(1 << kDebugShowMemoryUsage) | + //(1 << kDebugShowNops) | + //(1 << kDebugCountOpcodes) | + //(1 << kDebugDumpCheckStats) | + //(1 << kDebugDumpBitcodeFile) | + //(1 << kDebugVerifyBitcode) | + //(1 << kDebugShowSummaryMemoryUsage) | + 0; + +static CompiledMethod* CompileMethod(CompilerDriver& compiler, + const CompilerBackend compiler_backend, + const DexFile::CodeItem* code_item, + uint32_t access_flags, InvokeType invoke_type, + uint32_t class_def_idx, uint32_t method_idx, + jobject class_loader, const DexFile& dex_file +#if defined(ART_USE_PORTABLE_COMPILER) + , llvm::LlvmCompilationUnit* llvm_compilation_unit +#endif +) { + VLOG(compiler) << "Compiling " << PrettyMethod(method_idx, dex_file) << "..."; + + ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); + UniquePtr<CompilationUnit> cu(new CompilationUnit); + + cu->compiler_driver = &compiler; + cu->class_linker = class_linker; + cu->instruction_set = compiler.GetInstructionSet(); + cu->compiler_backend = compiler_backend; + DCHECK((cu->instruction_set == kThumb2) || + (cu->instruction_set == kX86) || + (cu->instruction_set == kMips)); + + + /* Adjust this value accordingly once inlining is performed */ + cu->num_dalvik_registers = code_item->registers_size_; + // TODO: set this from command line + cu->compiler_flip_match = false; + bool use_match = !cu->compiler_method_match.empty(); + bool match = use_match && (cu->compiler_flip_match ^ + (PrettyMethod(method_idx, dex_file).find(cu->compiler_method_match) != + std::string::npos)); + if (!use_match || match) { + cu->disable_opt = kCompilerOptimizerDisableFlags; + cu->enable_debug = kCompilerDebugFlags; + cu->verbose = VLOG_IS_ON(compiler) || + (cu->enable_debug & (1 << kDebugVerbose)); + } + + /* + * TODO: rework handling of optimization and debug flags. Should we split out + * MIR and backend flags? Need command-line setting as well. + */ + + if (compiler_backend == kPortable) { + // Fused long branches not currently usseful in bitcode. + cu->disable_opt |= (1 << kBranchFusing); + } + + if (cu->instruction_set == kMips) { + // Disable some optimizations for mips for now + cu->disable_opt |= ( + (1 << kLoadStoreElimination) | + (1 << kLoadHoisting) | + (1 << kSuppressLoads) | + (1 << kNullCheckElimination) | + (1 << kPromoteRegs) | + (1 << kTrackLiveTemps) | + (1 << kSafeOptimizations) | + (1 << kBBOpt) | + (1 << kMatch) | + (1 << kPromoteCompilerTemps)); + } + + cu->mir_graph.reset(new MIRGraph(cu.get(), &cu->arena)); + + /* Gathering opcode stats? */ + if (kCompilerDebugFlags & (1 << kDebugCountOpcodes)) { + cu->mir_graph->EnableOpcodeCounting(); + } + + /* Build the raw MIR graph */ + cu->mir_graph->InlineMethod(code_item, access_flags, invoke_type, class_def_idx, method_idx, + class_loader, dex_file); + + /* Do a code layout pass */ + cu->mir_graph->CodeLayout(); + + /* Perform SSA transformation for the whole method */ + cu->mir_graph->SSATransformation(); + + /* Do constant propagation */ + cu->mir_graph->PropagateConstants(); + + /* Count uses */ + cu->mir_graph->MethodUseCount(); + + /* Perform null check elimination */ + cu->mir_graph->NullCheckElimination(); + + /* Combine basic blocks where possible */ + cu->mir_graph->BasicBlockCombine(); + + /* Do some basic block optimizations */ + cu->mir_graph->BasicBlockOptimization(); + + if (cu->enable_debug & (1 << kDebugDumpCheckStats)) { + cu->mir_graph->DumpCheckStats(); + } + + if (kCompilerDebugFlags & (1 << kDebugCountOpcodes)) { + cu->mir_graph->ShowOpcodeStats(); + } + + /* Set up regLocation[] array to describe values - one for each ssa_name. */ + cu->mir_graph->BuildRegLocations(); + + CompiledMethod* result = NULL; + +#if defined(ART_USE_PORTABLE_COMPILER) + if (compiler_backend == kPortable) { + cu->cg.reset(PortableCodeGenerator(cu.get(), cu->mir_graph.get(), &cu->arena, + llvm_compilation_unit)); + } else +#endif + { + switch (compiler.GetInstructionSet()) { + case kThumb2: + cu->cg.reset(ArmCodeGenerator(cu.get(), cu->mir_graph.get(), &cu->arena)); break; + case kMips: + cu->cg.reset(MipsCodeGenerator(cu.get(), cu->mir_graph.get(), &cu->arena)); break; + case kX86: + cu->cg.reset(X86CodeGenerator(cu.get(), cu->mir_graph.get(), &cu->arena)); break; + default: + LOG(FATAL) << "Unexpected instruction set: " << compiler.GetInstructionSet(); + } + } + + cu->cg->Materialize(); + + result = cu->cg->GetCompiledMethod(); + + if (result) { + VLOG(compiler) << "Compiled " << PrettyMethod(method_idx, dex_file); + } else { + VLOG(compiler) << "Deferred " << PrettyMethod(method_idx, dex_file); + } + + if (cu->enable_debug & (1 << kDebugShowMemoryUsage)) { + if (cu->arena.BytesAllocated() > (5 * 1024 *1024)) { + MemStats mem_stats(cu->arena); + LOG(INFO) << PrettyMethod(method_idx, dex_file) << " " << Dumpable<MemStats>(mem_stats); + } + } + + if (cu->enable_debug & (1 << kDebugShowSummaryMemoryUsage)) { + LOG(INFO) << "MEMINFO " << cu->arena.BytesAllocated() << " " << cu->mir_graph->GetNumBlocks() + << " " << PrettyMethod(method_idx, dex_file); + } + + return result; +} + +CompiledMethod* CompileOneMethod(CompilerDriver& compiler, + const CompilerBackend backend, + const DexFile::CodeItem* code_item, + uint32_t access_flags, + InvokeType invoke_type, + uint32_t class_def_idx, + uint32_t method_idx, + jobject class_loader, + const DexFile& dex_file, + llvm::LlvmCompilationUnit* llvm_compilation_unit) { + return CompileMethod(compiler, backend, code_item, access_flags, invoke_type, class_def_idx, + method_idx, class_loader, dex_file +#if defined(ART_USE_PORTABLE_COMPILER) + , llvm_compilation_unit +#endif + ); +} + +} // namespace art + +extern "C" art::CompiledMethod* + ArtQuickCompileMethod(art::CompilerDriver& compiler, + const art::DexFile::CodeItem* code_item, + uint32_t access_flags, art::InvokeType invoke_type, + uint32_t class_def_idx, uint32_t method_idx, jobject class_loader, + const art::DexFile& dex_file) { + // TODO: check method fingerprint here to determine appropriate backend type. Until then, use build default + art::CompilerBackend backend = compiler.GetCompilerBackend(); + return art::CompileOneMethod(compiler, backend, code_item, access_flags, invoke_type, + class_def_idx, method_idx, class_loader, dex_file, + NULL /* use thread llvm_info */); +} |