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