Compiler.cpp revision 5b7f52aff2030d520ee2ac6d3ac7d917f38d550c
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 kErrHookBeforeExecuteLTOPasses: 68 return "Error occurred during beforeExecuteLTOPasses() in subclass."; 69 case kErrHookAfterExecuteLTOPasses: 70 return "Error occurred during afterExecuteLTOPasses() in subclass."; 71 case kErrHookBeforeAddCodeGenPasses: 72 return "Error occurred during beforeAddCodeGenPasses() in subclass."; 73 case kErrHookAfterAddCodeGenPasses: 74 return "Error occurred during afterAddCodeGenPasses() in subclass."; 75 case kErrHookBeforeExecuteCodeGenPasses: 76 return "Error occurred during beforeExecuteCodeGenPasses() in subclass."; 77 case kErrHookAfterExecuteCodeGenPasses: 78 return "Error occurred during afterExecuteCodeGenPasses() in subclass."; 79 case kErrInvalidSource: 80 return "Error loading input bitcode"; 81 } 82 83 // This assert should never be reached as the compiler verifies that the 84 // above switch coveres all enum values. 85 assert(false && "Unknown error code encountered"); 86 return ""; 87} 88 89//===----------------------------------------------------------------------===// 90// Instance Methods 91//===----------------------------------------------------------------------===// 92Compiler::Compiler() : mTarget(NULL), mEnableLTO(true) { 93 return; 94} 95 96Compiler::Compiler(const CompilerConfig &pConfig) : mTarget(NULL), 97 mEnableLTO(true) { 98 const std::string &triple = pConfig.getTriple(); 99 100 enum ErrorCode err = config(pConfig); 101 if (err != kSuccess) { 102 ALOGE("%s (%s, features: %s)", GetErrorString(err), 103 triple.c_str(), pConfig.getFeatureString().c_str()); 104 return; 105 } 106 107 return; 108} 109 110enum Compiler::ErrorCode Compiler::config(const CompilerConfig &pConfig) { 111 if (pConfig.getTarget() == NULL) { 112 return kInvalidConfigNoTarget; 113 } 114 115 llvm::TargetMachine *new_target = 116 (pConfig.getTarget())->createTargetMachine(pConfig.getTriple(), 117 pConfig.getCPU(), 118 pConfig.getFeatureString(), 119 pConfig.getTargetOptions(), 120 pConfig.getRelocationModel(), 121 pConfig.getCodeModel(), 122 pConfig.getOptimizationLevel()); 123 124 if (new_target == NULL) { 125 return ((mTarget != NULL) ? kErrSwitchTargetMachine : 126 kErrCreateTargetMachine); 127 } 128 129 // Replace the old TargetMachine. 130 delete mTarget; 131 mTarget = new_target; 132 133 // Adjust register allocation policy according to the optimization level. 134 // createFastRegisterAllocator: fast but bad quality 135 // createLinearScanRegisterAllocator: not so fast but good quality 136 if ((pConfig.getOptimizationLevel() == llvm::CodeGenOpt::None)) { 137 llvm::RegisterRegAlloc::setDefault(llvm::createFastRegisterAllocator); 138 } else { 139 llvm::RegisterRegAlloc::setDefault(llvm::createGreedyRegisterAllocator); 140 } 141 142 // Relax all machine instructions. 143 mTarget->setMCRelaxAll(true); 144 145 return kSuccess; 146} 147 148Compiler::~Compiler() { 149 delete mTarget; 150} 151 152enum Compiler::ErrorCode Compiler::runLTO(Script &pScript) { 153 llvm::DataLayout *data_layout = NULL; 154 155 // Pass manager for link-time optimization 156 llvm::PassManager lto_passes; 157 158 // Prepare DataLayout target data from Module 159 data_layout = new (std::nothrow) llvm::DataLayout(*mTarget->getDataLayout()); 160 if (data_layout == NULL) { 161 return kErrDataLayoutNoMemory; 162 } 163 164 // Add DataLayout to the pass manager. 165 lto_passes.add(data_layout); 166 167 // Invokde "beforeAddLTOPasses" before adding the first pass. 168 if (!beforeAddLTOPasses(pScript, lto_passes)) { 169 return kErrHookBeforeAddLTOPasses; 170 } 171 172 if (mTarget->getOptLevel() == llvm::CodeGenOpt::None) { 173 lto_passes.add(llvm::createGlobalOptimizerPass()); 174 lto_passes.add(llvm::createConstantMergePass()); 175 } else { 176 // FIXME: Figure out which passes should be executed. 177 llvm::PassManagerBuilder Builder; 178 Builder.populateLTOPassManager(lto_passes, /*Internalize*/false, 179 /*RunInliner*/true); 180 } 181 182 // Invokde "afterAddLTOPasses" after pass manager finished its 183 // construction. 184 if (!afterAddLTOPasses(pScript, lto_passes)) { 185 return kErrHookAfterAddLTOPasses; 186 } 187 188 // Invokde "beforeExecuteLTOPasses" before executing the passes. 189 if (!beforeExecuteLTOPasses(pScript, lto_passes)) { 190 return kErrHookBeforeExecuteLTOPasses; 191 } 192 193 lto_passes.run(pScript.getSource().getModule()); 194 195 // Invokde "afterExecuteLTOPasses" before returning. 196 if (!afterExecuteLTOPasses(pScript)) { 197 return kErrHookAfterExecuteLTOPasses; 198 } 199 200 return kSuccess; 201} 202 203enum Compiler::ErrorCode Compiler::runCodeGen(Script &pScript, 204 llvm::raw_ostream &pResult) { 205 llvm::DataLayout *data_layout; 206 llvm::MCContext *mc_context = NULL; 207 208 // Create pass manager for MC code generation. 209 llvm::PassManager codegen_passes; 210 211 // Prepare DataLayout target data from Module 212 data_layout = new (std::nothrow) llvm::DataLayout(*mTarget->getDataLayout()); 213 if (data_layout == NULL) { 214 return kErrDataLayoutNoMemory; 215 } 216 217 // Add DataLayout to the pass manager. 218 codegen_passes.add(data_layout); 219 220 // Invokde "beforeAddCodeGenPasses" before adding the first pass. 221 if (!beforeAddCodeGenPasses(pScript, codegen_passes)) { 222 return kErrHookBeforeAddCodeGenPasses; 223 } 224 225 // Add passes to the pass manager to emit machine code through MC layer. 226 if (mTarget->addPassesToEmitMC(codegen_passes, mc_context, pResult, 227 /* DisableVerify */false)) { 228 return kPrepareCodeGenPass; 229 } 230 231 // Invokde "afterAddCodeGenPasses" after pass manager finished its 232 // construction. 233 if (!afterAddCodeGenPasses(pScript, codegen_passes)) { 234 return kErrHookAfterAddCodeGenPasses; 235 } 236 237 // Invokde "beforeExecuteCodeGenPasses" before executing the passes. 238 if (!beforeExecuteCodeGenPasses(pScript, codegen_passes)) { 239 return kErrHookBeforeExecuteCodeGenPasses; 240 } 241 242 // Execute the pass. 243 codegen_passes.run(pScript.getSource().getModule()); 244 245 // Invokde "afterExecuteCodeGenPasses" before returning. 246 if (!afterExecuteCodeGenPasses(pScript)) { 247 return kErrHookAfterExecuteCodeGenPasses; 248 } 249 250 return kSuccess; 251} 252 253enum Compiler::ErrorCode Compiler::compile(Script &pScript, 254 llvm::raw_ostream &pResult, 255 llvm::raw_ostream *IRStream) { 256 llvm::Module &module = pScript.getSource().getModule(); 257 enum ErrorCode err; 258 259 if (mTarget == NULL) { 260 return kErrNoTargetMachine; 261 } 262 263 // Materialize the bitcode module. 264 if (module.getMaterializer() != NULL) { 265 std::string error; 266 // A module with non-null materializer means that it is a lazy-load module. 267 // Materialize it now via invoking MaterializeAllPermanently(). This 268 // function returns false when the materialization is successful. 269 if (module.MaterializeAllPermanently(&error)) { 270 ALOGE("Failed to materialize the module `%s'! (%s)", 271 module.getModuleIdentifier().c_str(), error.c_str()); 272 return kErrMaterialization; 273 } 274 } 275 276 if (mEnableLTO && ((err = runLTO(pScript)) != kSuccess)) { 277 return err; 278 } 279 280 if (IRStream) 281 *IRStream << module; 282 283 if ((err = runCodeGen(pScript, pResult)) != kSuccess) { 284 return err; 285 } 286 287 return kSuccess; 288} 289 290enum Compiler::ErrorCode Compiler::compile(Script &pScript, 291 OutputFile &pResult, 292 llvm::raw_ostream *IRStream) { 293 // Check the state of the specified output file. 294 if (pResult.hasError()) { 295 return kErrInvalidOutputFileState; 296 } 297 298 // Open the output file decorated in llvm::raw_ostream. 299 llvm::raw_ostream *out = pResult.dup(); 300 if (out == NULL) { 301 return kErrPrepareOutput; 302 } 303 304 // Delegate the request. 305 enum Compiler::ErrorCode err = compile(pScript, *out, IRStream); 306 307 // Close the output before return. 308 delete out; 309 310 return err; 311} 312