Compiler.cpp revision a630078b32eb37a8de91ae09e26babf235d4fc9f
1/* 2 * Copyright 2010-2012, 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 "bcc/Compiler.h" 18 19#include <llvm/Analysis/Passes.h> 20#include <llvm/CodeGen/RegAllocRegistry.h> 21#include <llvm/IR/Module.h> 22#include <llvm/PassManager.h> 23#include <llvm/Support/TargetRegistry.h> 24#include <llvm/Support/raw_ostream.h> 25#include <llvm/IR/DataLayout.h> 26#include <llvm/Target/TargetMachine.h> 27#include <llvm/Transforms/IPO.h> 28#include <llvm/Transforms/IPO/PassManagerBuilder.h> 29#include <llvm/Transforms/Scalar.h> 30 31#include "bcc/Script.h" 32#include "bcc/Source.h" 33#include "bcc/Support/CompilerConfig.h" 34#include "bcc/Support/Log.h" 35#include "bcc/Support/OutputFile.h" 36 37using namespace bcc; 38 39const char *Compiler::GetErrorString(enum ErrorCode pErrCode) { 40 switch (pErrCode) { 41 case kSuccess: 42 return "Successfully compiled."; 43 case kInvalidConfigNoTarget: 44 return "Invalid compiler config supplied (getTarget() returns NULL.) " 45 "(missing call to CompilerConfig::initialize()?)"; 46 case kErrCreateTargetMachine: 47 return "Failed to create llvm::TargetMachine."; 48 case kErrSwitchTargetMachine: 49 return "Failed to switch llvm::TargetMachine."; 50 case kErrNoTargetMachine: 51 return "Failed to compile the script since there's no available " 52 "TargetMachine. (missing call to Compiler::config()?)"; 53 case kErrDataLayoutNoMemory: 54 return "Out of memory when create DataLayout during compilation."; 55 case kErrMaterialization: 56 return "Failed to materialize the module."; 57 case kErrInvalidOutputFileState: 58 return "Supplied output file was invalid (in the error state.)"; 59 case kErrPrepareOutput: 60 return "Failed to prepare file for output."; 61 case kPrepareCodeGenPass: 62 return "Failed to construct pass list for code-generation."; 63 case kErrHookBeforeAddLTOPasses: 64 return "Error occurred during beforeAddLTOPasses() in subclass."; 65 case kErrHookAfterAddLTOPasses: 66 return "Error occurred during afterAddLTOPasses() in subclass."; 67 case kErrHookAfterExecuteLTOPasses: 68 return "Error occurred during afterExecuteLTOPasses() in subclass."; 69 case kErrHookBeforeAddCodeGenPasses: 70 return "Error occurred during beforeAddCodeGenPasses() in subclass."; 71 case kErrHookAfterAddCodeGenPasses: 72 return "Error occurred during afterAddCodeGenPasses() in subclass."; 73 case kErrHookBeforeExecuteCodeGenPasses: 74 return "Error occurred during beforeExecuteCodeGenPasses() in subclass."; 75 case kErrHookAfterExecuteCodeGenPasses: 76 return "Error occurred during afterExecuteCodeGenPasses() in subclass."; 77 case kErrInvalidSource: 78 return "Error loading input bitcode"; 79 } 80 81 // This assert should never be reached as the compiler verifies that the 82 // above switch coveres all enum values. 83 assert(false && "Unknown error code encountered"); 84 return ""; 85} 86 87//===----------------------------------------------------------------------===// 88// Instance Methods 89//===----------------------------------------------------------------------===// 90Compiler::Compiler() : mTarget(NULL), mEnableLTO(true) { 91 return; 92} 93 94Compiler::Compiler(const CompilerConfig &pConfig) : mTarget(NULL), 95 mEnableLTO(true) { 96 const std::string &triple = pConfig.getTriple(); 97 98 enum ErrorCode err = config(pConfig); 99 if (err != kSuccess) { 100 ALOGE("%s (%s, features: %s)", GetErrorString(err), 101 triple.c_str(), pConfig.getFeatureString().c_str()); 102 return; 103 } 104 105 return; 106} 107 108enum Compiler::ErrorCode Compiler::config(const CompilerConfig &pConfig) { 109 if (pConfig.getTarget() == NULL) { 110 return kInvalidConfigNoTarget; 111 } 112 113 llvm::TargetMachine *new_target = 114 (pConfig.getTarget())->createTargetMachine(pConfig.getTriple(), 115 pConfig.getCPU(), 116 pConfig.getFeatureString(), 117 pConfig.getTargetOptions(), 118 pConfig.getRelocationModel(), 119 pConfig.getCodeModel(), 120 pConfig.getOptimizationLevel()); 121 122 if (new_target == NULL) { 123 return ((mTarget != NULL) ? kErrSwitchTargetMachine : 124 kErrCreateTargetMachine); 125 } 126 127 // Replace the old TargetMachine. 128 delete mTarget; 129 mTarget = new_target; 130 131 // Adjust register allocation policy according to the optimization level. 132 // createFastRegisterAllocator: fast but bad quality 133 // createLinearScanRegisterAllocator: not so fast but good quality 134 if ((pConfig.getOptimizationLevel() == llvm::CodeGenOpt::None)) { 135 llvm::RegisterRegAlloc::setDefault(llvm::createFastRegisterAllocator); 136 } else { 137 llvm::RegisterRegAlloc::setDefault(llvm::createGreedyRegisterAllocator); 138 } 139 140 return kSuccess; 141} 142 143Compiler::~Compiler() { 144 delete mTarget; 145} 146 147enum Compiler::ErrorCode Compiler::runLTO(Script &pScript) { 148 llvm::DataLayoutPass *data_layout_pass = NULL; 149 150 // Pass manager for link-time optimization 151 llvm::PassManager lto_passes; 152 153 // Prepare DataLayout target data from Module 154 data_layout_pass = new (std::nothrow) llvm::DataLayoutPass(*mTarget->getDataLayout()); 155 if (data_layout_pass == NULL) { 156 return kErrDataLayoutNoMemory; 157 } 158 159 // Add DataLayout to the pass manager. 160 lto_passes.add(data_layout_pass); 161 162 // Invoke "beforeAddLTOPasses" before adding the first pass. 163 if (!beforeAddLTOPasses(pScript, lto_passes)) { 164 return kErrHookBeforeAddLTOPasses; 165 } 166 167 if (mTarget->getOptLevel() == llvm::CodeGenOpt::None) { 168 lto_passes.add(llvm::createGlobalOptimizerPass()); 169 lto_passes.add(llvm::createConstantMergePass()); 170 } else { 171 // FIXME: Figure out which passes should be executed. 172 llvm::PassManagerBuilder Builder; 173 Builder.populateLTOPassManager(lto_passes, /*Internalize*/false, 174 /*RunInliner*/true); 175 } 176 177 // Invoke "afterAddLTOPasses" after pass manager finished its 178 // construction. 179 if (!afterAddLTOPasses(pScript, lto_passes)) { 180 return kErrHookAfterAddLTOPasses; 181 } 182 183 lto_passes.run(pScript.getSource().getModule()); 184 185 // Invoke "afterExecuteLTOPasses" before returning. 186 if (!afterExecuteLTOPasses(pScript)) { 187 return kErrHookAfterExecuteLTOPasses; 188 } 189 190 return kSuccess; 191} 192 193enum Compiler::ErrorCode Compiler::runCodeGen(Script &pScript, 194 llvm::raw_ostream &pResult) { 195 llvm::DataLayoutPass *data_layout_pass; 196 llvm::MCContext *mc_context = NULL; 197 198 // Create pass manager for MC code generation. 199 llvm::PassManager codegen_passes; 200 201 // Prepare DataLayout target data from Module 202 data_layout_pass = new (std::nothrow) llvm::DataLayoutPass(*mTarget->getDataLayout()); 203 if (data_layout_pass == NULL) { 204 return kErrDataLayoutNoMemory; 205 } 206 207 // Add DataLayout to the pass manager. 208 codegen_passes.add(data_layout_pass); 209 210 // Invokde "beforeAddCodeGenPasses" before adding the first pass. 211 if (!beforeAddCodeGenPasses(pScript, codegen_passes)) { 212 return kErrHookBeforeAddCodeGenPasses; 213 } 214 215 // Add passes to the pass manager to emit machine code through MC layer. 216 if (mTarget->addPassesToEmitMC(codegen_passes, mc_context, pResult, 217 /* DisableVerify */false)) { 218 return kPrepareCodeGenPass; 219 } 220 221 // Invokde "afterAddCodeGenPasses" after pass manager finished its 222 // construction. 223 if (!afterAddCodeGenPasses(pScript, codegen_passes)) { 224 return kErrHookAfterAddCodeGenPasses; 225 } 226 227 // Invokde "beforeExecuteCodeGenPasses" before executing the passes. 228 if (!beforeExecuteCodeGenPasses(pScript, codegen_passes)) { 229 return kErrHookBeforeExecuteCodeGenPasses; 230 } 231 232 // Execute the pass. 233 codegen_passes.run(pScript.getSource().getModule()); 234 235 // Invokde "afterExecuteCodeGenPasses" before returning. 236 if (!afterExecuteCodeGenPasses(pScript)) { 237 return kErrHookAfterExecuteCodeGenPasses; 238 } 239 240 return kSuccess; 241} 242 243enum Compiler::ErrorCode Compiler::compile(Script &pScript, 244 llvm::raw_ostream &pResult, 245 llvm::raw_ostream *IRStream) { 246 llvm::Module &module = pScript.getSource().getModule(); 247 enum ErrorCode err; 248 249 if (mTarget == NULL) { 250 return kErrNoTargetMachine; 251 } 252 253 // Materialize the bitcode module. 254 if (module.getMaterializer() != NULL) { 255 // A module with non-null materializer means that it is a lazy-load module. 256 // Materialize it now via invoking MaterializeAllPermanently(). This 257 // function returns false when the materialization is successful. 258 llvm::error_code ec = module.materializeAllPermanently(); 259 if (ec) { 260 ALOGE("Failed to materialize the module `%s'! (%s)", 261 module.getModuleIdentifier().c_str(), ec.message().c_str()); 262 return kErrMaterialization; 263 } 264 } 265 266 if (mEnableLTO && ((err = runLTO(pScript)) != kSuccess)) { 267 return err; 268 } 269 270 if (IRStream) 271 *IRStream << module; 272 273 if ((err = runCodeGen(pScript, pResult)) != kSuccess) { 274 return err; 275 } 276 277 return kSuccess; 278} 279 280enum Compiler::ErrorCode Compiler::compile(Script &pScript, 281 OutputFile &pResult, 282 llvm::raw_ostream *IRStream) { 283 // Check the state of the specified output file. 284 if (pResult.hasError()) { 285 return kErrInvalidOutputFileState; 286 } 287 288 // Open the output file decorated in llvm::raw_ostream. 289 llvm::raw_ostream *out = pResult.dup(); 290 if (out == NULL) { 291 return kErrPrepareOutput; 292 } 293 294 // Delegate the request. 295 enum Compiler::ErrorCode err = compile(pScript, *out, IRStream); 296 297 // Close the output before return. 298 delete out; 299 300 return err; 301} 302