frontend.cc revision f69863b3039fc621ff4250e262d2a024d5e79ec8
1/* 2 * Copyright (C) 2011 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 <llvm/Support/Threading.h> 18 19#include "compiler_internals.h" 20#include "driver/compiler_driver.h" 21#include "dataflow_iterator-inl.h" 22#include "leb128.h" 23#include "mirror/object.h" 24#include "runtime.h" 25#include "backend.h" 26#include "base/logging.h" 27 28#if defined(ART_USE_PORTABLE_COMPILER) 29#include "dex/portable/mir_to_gbc.h" 30#include "llvm/llvm_compilation_unit.h" 31#endif 32 33namespace { 34#if !defined(ART_USE_PORTABLE_COMPILER) 35 pthread_once_t llvm_multi_init = PTHREAD_ONCE_INIT; 36#endif 37 void InitializeLLVMForQuick() { 38 ::llvm::llvm_start_multithreaded(); 39 } 40} 41 42namespace art { 43namespace llvm { 44::llvm::Module* makeLLVMModuleContents(::llvm::Module* module); 45} 46 47LLVMInfo::LLVMInfo() { 48#if !defined(ART_USE_PORTABLE_COMPILER) 49 pthread_once(&llvm_multi_init, InitializeLLVMForQuick); 50#endif 51 // Create context, module, intrinsic helper & ir builder 52 llvm_context_.reset(new ::llvm::LLVMContext()); 53 llvm_module_ = new ::llvm::Module("art", *llvm_context_); 54 ::llvm::StructType::create(*llvm_context_, "JavaObject"); 55 art::llvm::makeLLVMModuleContents(llvm_module_); 56 intrinsic_helper_.reset( new art::llvm::IntrinsicHelper(*llvm_context_, *llvm_module_)); 57 ir_builder_.reset(new art::llvm::IRBuilder(*llvm_context_, *llvm_module_, *intrinsic_helper_)); 58} 59 60LLVMInfo::~LLVMInfo() { 61} 62 63extern "C" void ArtInitQuickCompilerContext(art::CompilerDriver& compiler) { 64 CHECK(compiler.GetCompilerContext() == NULL); 65 LLVMInfo* llvm_info = new LLVMInfo(); 66 compiler.SetCompilerContext(llvm_info); 67} 68 69extern "C" void ArtUnInitQuickCompilerContext(art::CompilerDriver& compiler) { 70 delete reinterpret_cast<LLVMInfo*>(compiler.GetCompilerContext()); 71 compiler.SetCompilerContext(NULL); 72} 73 74/* Default optimizer/debug setting for the compiler. */ 75static uint32_t kCompilerOptimizerDisableFlags = 0 | // Disable specific optimizations 76 (1 << kLoadStoreElimination) | 77 //(1 << kLoadHoisting) | 78 //(1 << kSuppressLoads) | 79 //(1 << kNullCheckElimination) | 80 //(1 << kPromoteRegs) | 81 //(1 << kTrackLiveTemps) | 82 //(1 << kSafeOptimizations) | 83 //(1 << kBBOpt) | 84 //(1 << kMatch) | 85 //(1 << kPromoteCompilerTemps) | 86 0; 87 88static uint32_t kCompilerDebugFlags = 0 | // Enable debug/testing modes 89 //(1 << kDebugDisplayMissingTargets) | 90 //(1 << kDebugVerbose) | 91 //(1 << kDebugDumpCFG) | 92 //(1 << kDebugSlowFieldPath) | 93 //(1 << kDebugSlowInvokePath) | 94 //(1 << kDebugSlowStringPath) | 95 //(1 << kDebugSlowestFieldPath) | 96 //(1 << kDebugSlowestStringPath) | 97 //(1 << kDebugExerciseResolveMethod) | 98 //(1 << kDebugVerifyDataflow) | 99 //(1 << kDebugShowMemoryUsage) | 100 //(1 << kDebugShowNops) | 101 //(1 << kDebugCountOpcodes) | 102 //(1 << kDebugDumpCheckStats) | 103 //(1 << kDebugDumpBitcodeFile) | 104 //(1 << kDebugVerifyBitcode) | 105 //(1 << kDebugShowSummaryMemoryUsage) | 106 0; 107 108static CompiledMethod* CompileMethod(CompilerDriver& compiler, 109 const CompilerBackend compiler_backend, 110 const DexFile::CodeItem* code_item, 111 uint32_t access_flags, InvokeType invoke_type, 112 uint32_t class_def_idx, uint32_t method_idx, 113 jobject class_loader, const DexFile& dex_file 114#if defined(ART_USE_PORTABLE_COMPILER) 115 , llvm::LlvmCompilationUnit* llvm_compilation_unit 116#endif 117) { 118 VLOG(compiler) << "Compiling " << PrettyMethod(method_idx, dex_file) << "..."; 119 120 ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); 121 UniquePtr<CompilationUnit> cu(new CompilationUnit); 122 123 cu->compiler_driver = &compiler; 124 cu->class_linker = class_linker; 125 cu->instruction_set = compiler.GetInstructionSet(); 126 cu->compiler_backend = compiler_backend; 127 DCHECK((cu->instruction_set == kThumb2) || 128 (cu->instruction_set == kX86) || 129 (cu->instruction_set == kMips)); 130 131 132 /* Adjust this value accordingly once inlining is performed */ 133 cu->num_dalvik_registers = code_item->registers_size_; 134 // TODO: set this from command line 135 cu->compiler_flip_match = false; 136 bool use_match = !cu->compiler_method_match.empty(); 137 bool match = use_match && (cu->compiler_flip_match ^ 138 (PrettyMethod(method_idx, dex_file).find(cu->compiler_method_match) != 139 std::string::npos)); 140 if (!use_match || match) { 141 cu->disable_opt = kCompilerOptimizerDisableFlags; 142 cu->enable_debug = kCompilerDebugFlags; 143 cu->verbose = VLOG_IS_ON(compiler) || 144 (cu->enable_debug & (1 << kDebugVerbose)); 145 } 146 147 /* 148 * TODO: rework handling of optimization and debug flags. Should we split out 149 * MIR and backend flags? Need command-line setting as well. 150 */ 151 152 if (compiler_backend == kPortable) { 153 // Fused long branches not currently usseful in bitcode. 154 cu->disable_opt |= (1 << kBranchFusing); 155 } 156 157 if (cu->instruction_set == kMips) { 158 // Disable some optimizations for mips for now 159 cu->disable_opt |= ( 160 (1 << kLoadStoreElimination) | 161 (1 << kLoadHoisting) | 162 (1 << kSuppressLoads) | 163 (1 << kNullCheckElimination) | 164 (1 << kPromoteRegs) | 165 (1 << kTrackLiveTemps) | 166 (1 << kSafeOptimizations) | 167 (1 << kBBOpt) | 168 (1 << kMatch) | 169 (1 << kPromoteCompilerTemps)); 170 } 171 172 cu->mir_graph.reset(new MIRGraph(cu.get(), &cu->arena)); 173 174 /* Gathering opcode stats? */ 175 if (kCompilerDebugFlags & (1 << kDebugCountOpcodes)) { 176 cu->mir_graph->EnableOpcodeCounting(); 177 } 178 179 /* Build the raw MIR graph */ 180 cu->mir_graph->InlineMethod(code_item, access_flags, invoke_type, class_def_idx, method_idx, 181 class_loader, dex_file); 182 183 /* Do a code layout pass */ 184 cu->mir_graph->CodeLayout(); 185 186 /* Perform SSA transformation for the whole method */ 187 cu->mir_graph->SSATransformation(); 188 189 /* Do constant propagation */ 190 cu->mir_graph->PropagateConstants(); 191 192 /* Count uses */ 193 cu->mir_graph->MethodUseCount(); 194 195 /* Perform null check elimination */ 196 cu->mir_graph->NullCheckElimination(); 197 198 /* Combine basic blocks where possible */ 199 cu->mir_graph->BasicBlockCombine(); 200 201 /* Do some basic block optimizations */ 202 cu->mir_graph->BasicBlockOptimization(); 203 204 if (cu->enable_debug & (1 << kDebugDumpCheckStats)) { 205 cu->mir_graph->DumpCheckStats(); 206 } 207 208 if (kCompilerDebugFlags & (1 << kDebugCountOpcodes)) { 209 cu->mir_graph->ShowOpcodeStats(); 210 } 211 212 /* Set up regLocation[] array to describe values - one for each ssa_name. */ 213 cu->mir_graph->BuildRegLocations(); 214 215 CompiledMethod* result = NULL; 216 217#if defined(ART_USE_PORTABLE_COMPILER) 218 if (compiler_backend == kPortable) { 219 cu->cg.reset(PortableCodeGenerator(cu.get(), cu->mir_graph.get(), &cu->arena, 220 llvm_compilation_unit)); 221 } else 222#endif 223 { // NOLINT(whitespace/braces) 224 switch (compiler.GetInstructionSet()) { 225 case kThumb2: 226 cu->cg.reset(ArmCodeGenerator(cu.get(), cu->mir_graph.get(), &cu->arena)); 227 break; 228 case kMips: 229 cu->cg.reset(MipsCodeGenerator(cu.get(), cu->mir_graph.get(), &cu->arena)); 230 break; 231 case kX86: 232 cu->cg.reset(X86CodeGenerator(cu.get(), cu->mir_graph.get(), &cu->arena)); 233 break; 234 default: 235 LOG(FATAL) << "Unexpected instruction set: " << compiler.GetInstructionSet(); 236 } 237 } 238 239 cu->cg->Materialize(); 240 241 result = cu->cg->GetCompiledMethod(); 242 243 if (result) { 244 VLOG(compiler) << "Compiled " << PrettyMethod(method_idx, dex_file); 245 } else { 246 VLOG(compiler) << "Deferred " << PrettyMethod(method_idx, dex_file); 247 } 248 249 if (cu->enable_debug & (1 << kDebugShowMemoryUsage)) { 250 if (cu->arena.BytesAllocated() > (5 * 1024 *1024)) { 251 MemStats mem_stats(cu->arena); 252 LOG(INFO) << PrettyMethod(method_idx, dex_file) << " " << Dumpable<MemStats>(mem_stats); 253 } 254 } 255 256 if (cu->enable_debug & (1 << kDebugShowSummaryMemoryUsage)) { 257 LOG(INFO) << "MEMINFO " << cu->arena.BytesAllocated() << " " << cu->mir_graph->GetNumBlocks() 258 << " " << PrettyMethod(method_idx, dex_file); 259 } 260 261 return result; 262} 263 264CompiledMethod* CompileOneMethod(CompilerDriver& compiler, 265 const CompilerBackend backend, 266 const DexFile::CodeItem* code_item, 267 uint32_t access_flags, 268 InvokeType invoke_type, 269 uint32_t class_def_idx, 270 uint32_t method_idx, 271 jobject class_loader, 272 const DexFile& dex_file, 273 llvm::LlvmCompilationUnit* llvm_compilation_unit) { 274 return CompileMethod(compiler, backend, code_item, access_flags, invoke_type, class_def_idx, 275 method_idx, class_loader, dex_file 276#if defined(ART_USE_PORTABLE_COMPILER) 277 , llvm_compilation_unit 278#endif 279 ); 280} 281 282} // namespace art 283 284extern "C" art::CompiledMethod* 285 ArtQuickCompileMethod(art::CompilerDriver& compiler, 286 const art::DexFile::CodeItem* code_item, 287 uint32_t access_flags, art::InvokeType invoke_type, 288 uint32_t class_def_idx, uint32_t method_idx, jobject class_loader, 289 const art::DexFile& dex_file) { 290 // TODO: check method fingerprint here to determine appropriate backend type. Until then, use build default 291 art::CompilerBackend backend = compiler.GetCompilerBackend(); 292 return art::CompileOneMethod(compiler, backend, code_item, access_flags, invoke_type, 293 class_def_idx, method_idx, class_loader, dex_file, 294 NULL /* use thread llvm_info */); 295} 296