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 // Relax all machine instructions. 141 mTarget->setMCRelaxAll(true); 142 143 return kSuccess; 144} 145 146Compiler::~Compiler() { 147 delete mTarget; 148} 149 150enum Compiler::ErrorCode Compiler::runLTO(Script &pScript) { 151 llvm::DataLayout *data_layout = NULL; 152 153 // Pass manager for link-time optimization 154 llvm::PassManager lto_passes; 155 156 // Prepare DataLayout target data from Module 157 data_layout = new (std::nothrow) llvm::DataLayout(*mTarget->getDataLayout()); 158 if (data_layout == NULL) { 159 return kErrDataLayoutNoMemory; 160 } 161 162 // Add DataLayout to the pass manager. 163 lto_passes.add(data_layout); 164 165 // Invoke "beforeAddLTOPasses" before adding the first pass. 166 if (!beforeAddLTOPasses(pScript, lto_passes)) { 167 return kErrHookBeforeAddLTOPasses; 168 } 169 170 if (mTarget->getOptLevel() == llvm::CodeGenOpt::None) { 171 lto_passes.add(llvm::createGlobalOptimizerPass()); 172 lto_passes.add(llvm::createConstantMergePass()); 173 } else { 174 // FIXME: Figure out which passes should be executed. 175 llvm::PassManagerBuilder Builder; 176 Builder.populateLTOPassManager(lto_passes, /*Internalize*/false, 177 /*RunInliner*/true); 178 } 179 180 // Invoke "afterAddLTOPasses" after pass manager finished its 181 // construction. 182 if (!afterAddLTOPasses(pScript, lto_passes)) { 183 return kErrHookAfterAddLTOPasses; 184 } 185 186 lto_passes.run(pScript.getSource().getModule()); 187 188 // Invoke "afterExecuteLTOPasses" before returning. 189 if (!afterExecuteLTOPasses(pScript)) { 190 return kErrHookAfterExecuteLTOPasses; 191 } 192 193 return kSuccess; 194} 195 196enum Compiler::ErrorCode Compiler::runCodeGen(Script &pScript, 197 llvm::raw_ostream &pResult) { 198 llvm::DataLayout *data_layout; 199 llvm::MCContext *mc_context = NULL; 200 201 // Create pass manager for MC code generation. 202 llvm::PassManager codegen_passes; 203 204 // Prepare DataLayout target data from Module 205 data_layout = new (std::nothrow) llvm::DataLayout(*mTarget->getDataLayout()); 206 if (data_layout == NULL) { 207 return kErrDataLayoutNoMemory; 208 } 209 210 // Add DataLayout to the pass manager. 211 codegen_passes.add(data_layout); 212 213 // Invokde "beforeAddCodeGenPasses" before adding the first pass. 214 if (!beforeAddCodeGenPasses(pScript, codegen_passes)) { 215 return kErrHookBeforeAddCodeGenPasses; 216 } 217 218 // Add passes to the pass manager to emit machine code through MC layer. 219 if (mTarget->addPassesToEmitMC(codegen_passes, mc_context, pResult, 220 /* DisableVerify */false)) { 221 return kPrepareCodeGenPass; 222 } 223 224 // Invokde "afterAddCodeGenPasses" after pass manager finished its 225 // construction. 226 if (!afterAddCodeGenPasses(pScript, codegen_passes)) { 227 return kErrHookAfterAddCodeGenPasses; 228 } 229 230 // Invokde "beforeExecuteCodeGenPasses" before executing the passes. 231 if (!beforeExecuteCodeGenPasses(pScript, codegen_passes)) { 232 return kErrHookBeforeExecuteCodeGenPasses; 233 } 234 235 // Execute the pass. 236 codegen_passes.run(pScript.getSource().getModule()); 237 238 // Invokde "afterExecuteCodeGenPasses" before returning. 239 if (!afterExecuteCodeGenPasses(pScript)) { 240 return kErrHookAfterExecuteCodeGenPasses; 241 } 242 243 return kSuccess; 244} 245 246enum Compiler::ErrorCode Compiler::compile(Script &pScript, 247 llvm::raw_ostream &pResult, 248 llvm::raw_ostream *IRStream) { 249 llvm::Module &module = pScript.getSource().getModule(); 250 enum ErrorCode err; 251 252 if (mTarget == NULL) { 253 return kErrNoTargetMachine; 254 } 255 256 // Materialize the bitcode module. 257 if (module.getMaterializer() != NULL) { 258 std::string error; 259 // A module with non-null materializer means that it is a lazy-load module. 260 // Materialize it now via invoking MaterializeAllPermanently(). This 261 // function returns false when the materialization is successful. 262 if (module.MaterializeAllPermanently(&error)) { 263 ALOGE("Failed to materialize the module `%s'! (%s)", 264 module.getModuleIdentifier().c_str(), error.c_str()); 265 return kErrMaterialization; 266 } 267 } 268 269 if (mEnableLTO && ((err = runLTO(pScript)) != kSuccess)) { 270 return err; 271 } 272 273 if (IRStream) 274 *IRStream << module; 275 276 if ((err = runCodeGen(pScript, pResult)) != kSuccess) { 277 return err; 278 } 279 280 return kSuccess; 281} 282 283enum Compiler::ErrorCode Compiler::compile(Script &pScript, 284 OutputFile &pResult, 285 llvm::raw_ostream *IRStream) { 286 // Check the state of the specified output file. 287 if (pResult.hasError()) { 288 return kErrInvalidOutputFileState; 289 } 290 291 // Open the output file decorated in llvm::raw_ostream. 292 llvm::raw_ostream *out = pResult.dup(); 293 if (out == NULL) { 294 return kErrPrepareOutput; 295 } 296 297 // Delegate the request. 298 enum Compiler::ErrorCode err = compile(pScript, *out, IRStream); 299 300 // Close the output before return. 301 delete out; 302 303 return err; 304} 305