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 37 #include <string> 38 39 using namespace bcc; 40 41 const char *Compiler::GetErrorString(enum ErrorCode pErrCode) { 42 switch (pErrCode) { 43 case kSuccess: 44 return "Successfully compiled."; 45 case kInvalidConfigNoTarget: 46 return "Invalid compiler config supplied (getTarget() returns NULL.) " 47 "(missing call to CompilerConfig::initialize()?)"; 48 case kErrCreateTargetMachine: 49 return "Failed to create llvm::TargetMachine."; 50 case kErrSwitchTargetMachine: 51 return "Failed to switch llvm::TargetMachine."; 52 case kErrNoTargetMachine: 53 return "Failed to compile the script since there's no available " 54 "TargetMachine. (missing call to Compiler::config()?)"; 55 case kErrDataLayoutNoMemory: 56 return "Out of memory when create DataLayout during compilation."; 57 case kErrMaterialization: 58 return "Failed to materialize the module."; 59 case kErrInvalidOutputFileState: 60 return "Supplied output file was invalid (in the error state.)"; 61 case kErrPrepareOutput: 62 return "Failed to prepare file for output."; 63 case kPrepareCodeGenPass: 64 return "Failed to construct pass list for code-generation."; 65 case kErrHookBeforeAddLTOPasses: 66 return "Error occurred during beforeAddLTOPasses() in subclass."; 67 case kErrHookAfterAddLTOPasses: 68 return "Error occurred during afterAddLTOPasses() 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 //===----------------------------------------------------------------------===// 92 Compiler::Compiler() : mTarget(NULL), mEnableLTO(true) { 93 return; 94 } 95 96 Compiler::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 110 enum 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 return kSuccess; 143 } 144 145 Compiler::~Compiler() { 146 delete mTarget; 147 } 148 149 enum Compiler::ErrorCode Compiler::runLTO(Script &pScript) { 150 llvm::DataLayoutPass *data_layout_pass = NULL; 151 152 // Pass manager for link-time optimization 153 llvm::PassManager lto_passes; 154 155 // Prepare DataLayout target data from Module 156 data_layout_pass = new (std::nothrow) llvm::DataLayoutPass(*mTarget->getDataLayout()); 157 if (data_layout_pass == NULL) { 158 return kErrDataLayoutNoMemory; 159 } 160 161 // Add DataLayout to the pass manager. 162 lto_passes.add(data_layout_pass); 163 164 // Invoke "beforeAddLTOPasses" before adding the first pass. 165 if (!beforeAddLTOPasses(pScript, lto_passes)) { 166 return kErrHookBeforeAddLTOPasses; 167 } 168 169 if (mTarget->getOptLevel() == llvm::CodeGenOpt::None) { 170 lto_passes.add(llvm::createGlobalOptimizerPass()); 171 lto_passes.add(llvm::createConstantMergePass()); 172 } else { 173 // FIXME: Figure out which passes should be executed. 174 llvm::PassManagerBuilder Builder; 175 Builder.populateLTOPassManager(lto_passes, /*Internalize*/false, 176 /*RunInliner*/true); 177 } 178 179 // Invoke "afterAddLTOPasses" after pass manager finished its 180 // construction. 181 if (!afterAddLTOPasses(pScript, lto_passes)) { 182 return kErrHookAfterAddLTOPasses; 183 } 184 185 lto_passes.run(pScript.getSource().getModule()); 186 187 // Invoke "afterExecuteLTOPasses" before returning. 188 if (!afterExecuteLTOPasses(pScript)) { 189 return kErrHookAfterExecuteLTOPasses; 190 } 191 192 return kSuccess; 193 } 194 195 enum Compiler::ErrorCode Compiler::runCodeGen(Script &pScript, 196 llvm::raw_ostream &pResult) { 197 llvm::DataLayoutPass *data_layout_pass; 198 llvm::MCContext *mc_context = NULL; 199 200 // Create pass manager for MC code generation. 201 llvm::PassManager codegen_passes; 202 203 // Prepare DataLayout target data from Module 204 data_layout_pass = new (std::nothrow) llvm::DataLayoutPass(*mTarget->getDataLayout()); 205 if (data_layout_pass == NULL) { 206 return kErrDataLayoutNoMemory; 207 } 208 209 // Add DataLayout to the pass manager. 210 codegen_passes.add(data_layout_pass); 211 212 // Invokde "beforeAddCodeGenPasses" before adding the first pass. 213 if (!beforeAddCodeGenPasses(pScript, codegen_passes)) { 214 return kErrHookBeforeAddCodeGenPasses; 215 } 216 217 // Add passes to the pass manager to emit machine code through MC layer. 218 if (mTarget->addPassesToEmitMC(codegen_passes, mc_context, pResult, 219 /* DisableVerify */false)) { 220 return kPrepareCodeGenPass; 221 } 222 223 // Invokde "afterAddCodeGenPasses" after pass manager finished its 224 // construction. 225 if (!afterAddCodeGenPasses(pScript, codegen_passes)) { 226 return kErrHookAfterAddCodeGenPasses; 227 } 228 229 // Invokde "beforeExecuteCodeGenPasses" before executing the passes. 230 if (!beforeExecuteCodeGenPasses(pScript, codegen_passes)) { 231 return kErrHookBeforeExecuteCodeGenPasses; 232 } 233 234 // Execute the pass. 235 codegen_passes.run(pScript.getSource().getModule()); 236 237 // Invokde "afterExecuteCodeGenPasses" before returning. 238 if (!afterExecuteCodeGenPasses(pScript)) { 239 return kErrHookAfterExecuteCodeGenPasses; 240 } 241 242 return kSuccess; 243 } 244 245 enum Compiler::ErrorCode Compiler::compile(Script &pScript, 246 llvm::raw_ostream &pResult, 247 llvm::raw_ostream *IRStream) { 248 llvm::Module &module = pScript.getSource().getModule(); 249 enum ErrorCode err; 250 251 if (mTarget == NULL) { 252 return kErrNoTargetMachine; 253 } 254 255 const std::string &triple = module.getTargetTriple(); 256 const llvm::DataLayout *dl = getTargetMachine().getDataLayout(); 257 unsigned int pointerSize = dl->getPointerSizeInBits(); 258 if (triple == "armv7-none-linux-gnueabi") { 259 if (pointerSize != 32) { 260 return kErrInvalidSource; 261 } 262 } else if (triple == "aarch64-none-linux-gnueabi") { 263 if (pointerSize != 64) { 264 return kErrInvalidSource; 265 } 266 } else { 267 return kErrInvalidSource; 268 } 269 270 // Materialize the bitcode module. 271 if (module.getMaterializer() != NULL) { 272 // A module with non-null materializer means that it is a lazy-load module. 273 // Materialize it now via invoking MaterializeAllPermanently(). This 274 // function returns false when the materialization is successful. 275 std::error_code ec = module.materializeAllPermanently(); 276 if (ec) { 277 ALOGE("Failed to materialize the module `%s'! (%s)", 278 module.getModuleIdentifier().c_str(), ec.message().c_str()); 279 return kErrMaterialization; 280 } 281 } 282 283 if (mEnableLTO && ((err = runLTO(pScript)) != kSuccess)) { 284 return err; 285 } 286 287 if (IRStream) 288 *IRStream << module; 289 290 if ((err = runCodeGen(pScript, pResult)) != kSuccess) { 291 return err; 292 } 293 294 return kSuccess; 295 } 296 297 enum Compiler::ErrorCode Compiler::compile(Script &pScript, 298 OutputFile &pResult, 299 llvm::raw_ostream *IRStream) { 300 // Check the state of the specified output file. 301 if (pResult.hasError()) { 302 return kErrInvalidOutputFileState; 303 } 304 305 // Open the output file decorated in llvm::raw_ostream. 306 llvm::raw_ostream *out = pResult.dup(); 307 if (out == NULL) { 308 return kErrPrepareOutput; 309 } 310 311 // Delegate the request. 312 enum Compiler::ErrorCode err = compile(pScript, *out, IRStream); 313 314 // Close the output before return. 315 delete out; 316 317 return err; 318 } 319