Logan | 1f028c0 | 2010-11-27 01:02:48 +0800 | [diff] [blame] | 1 | /* |
Stephen Hines | db16918 | 2012-01-05 18:46:36 -0800 | [diff] [blame] | 2 | * Copyright 2010-2012, The Android Open Source Project |
Logan | 1f028c0 | 2010-11-27 01:02:48 +0800 | [diff] [blame] | 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 | |
Logan | c439523 | 2010-11-27 18:54:17 +0800 | [diff] [blame] | 17 | #include "Compiler.h" |
Logan | 1f028c0 | 2010-11-27 01:02:48 +0800 | [diff] [blame] | 18 | |
Zonr Chang | fef9a1b | 2012-04-13 15:58:24 +0800 | [diff] [blame] | 19 | #include <llvm/Analysis/Passes.h> |
| 20 | #include <llvm/CodeGen/RegAllocRegistry.h> |
| 21 | #include <llvm/Module.h> |
| 22 | #include <llvm/PassManager.h> |
| 23 | #include <llvm/Support/TargetRegistry.h> |
| 24 | #include <llvm/Support/raw_ostream.h> |
| 25 | #include <llvm/Target/TargetData.h> |
| 26 | #include <llvm/Target/TargetMachine.h> |
| 27 | #include <llvm/Transforms/IPO.h> |
| 28 | #include <llvm/Transforms/Scalar.h> |
Logan | 3584900 | 2011-01-15 07:30:43 +0800 | [diff] [blame] | 29 | |
Zonr Chang | fef9a1b | 2012-04-13 15:58:24 +0800 | [diff] [blame] | 30 | #include "CompilerConfig.h" |
Logan | 4dcd679 | 2011-02-28 05:12:00 +0800 | [diff] [blame] | 31 | #include "DebugHelper.h" |
Zonr Chang | fef9a1b | 2012-04-13 15:58:24 +0800 | [diff] [blame] | 32 | #include "OutputFile.h" |
| 33 | #include "Script.h" |
| 34 | #include "Source.h" |
Logan | eb3d12b | 2010-12-16 06:20:18 +0800 | [diff] [blame] | 35 | |
Zonr Chang | fef9a1b | 2012-04-13 15:58:24 +0800 | [diff] [blame] | 36 | using namespace bcc; |
Logan Chien | da5e0c3 | 2011-06-13 03:47:21 +0800 | [diff] [blame] | 37 | |
Zonr Chang | fef9a1b | 2012-04-13 15:58:24 +0800 | [diff] [blame] | 38 | const char *Compiler::GetErrorString(enum ErrorCode pErrCode) { |
| 39 | static const char *ErrorString[] = { |
| 40 | /* kSuccess */ |
| 41 | "Successfully compiled.", |
| 42 | /* kInvalidConfigNoTarget */ |
| 43 | "Invalid compiler config supplied (getTarget() returns NULL.) " |
| 44 | "(missing call to CompilerConfig::initialize()?)", |
| 45 | /* kErrCreateTargetMachine */ |
| 46 | "Failed to create llvm::TargetMachine.", |
| 47 | /* kErrSwitchTargetMachine */ |
| 48 | "Failed to switch llvm::TargetMachine.", |
| 49 | /* kErrNoTargetMachine */ |
| 50 | "Failed to compile the script since there's no available TargetMachine." |
| 51 | " (missing call to Compiler::config()?)", |
| 52 | /* kErrTargetDataNoMemory */ |
| 53 | "Out of memory when create TargetData during compilation.", |
| 54 | /* kErrMaterialization */ |
| 55 | "Failed to materialize the module.", |
| 56 | /* kErrInvalidOutputFileState */ |
| 57 | "Supplied output file was invalid (in the error state.)", |
| 58 | /* kErrPrepareOutput */ |
| 59 | "Failed to prepare file for output.", |
| 60 | /* kPrepareCodeGenPass */ |
| 61 | "Failed to construct pass list for code-generation.", |
Stephen Hines | db16918 | 2012-01-05 18:46:36 -0800 | [diff] [blame] | 62 | |
Zonr Chang | fef9a1b | 2012-04-13 15:58:24 +0800 | [diff] [blame] | 63 | /* kErrHookBeforeAddLTOPasses */ |
| 64 | "Error occurred during beforeAddLTOPasses() in subclass.", |
| 65 | /* kErrHookAfterAddLTOPasses */ |
| 66 | "Error occurred during afterAddLTOPasses() in subclass.", |
| 67 | /* kErrHookBeforeExecuteLTOPasses */ |
| 68 | "Error occurred during beforeExecuteLTOPasses() in subclass.", |
| 69 | /* kErrHookAfterExecuteLTOPasses */ |
| 70 | "Error occurred during afterExecuteLTOPasses() in subclass.", |
Logan | 1f028c0 | 2010-11-27 01:02:48 +0800 | [diff] [blame] | 71 | |
Zonr Chang | fef9a1b | 2012-04-13 15:58:24 +0800 | [diff] [blame] | 72 | /* kErrHookBeforeAddCodeGenPasses */ |
| 73 | "Error occurred during beforeAddCodeGenPasses() in subclass.", |
| 74 | /* kErrHookAfterAddCodeGenPasses */ |
| 75 | "Error occurred during afterAddCodeGenPasses() in subclass.", |
| 76 | /* kErrHookBeforeExecuteCodeGenPasses */ |
| 77 | "Error occurred during beforeExecuteCodeGenPasses() in subclass.", |
| 78 | /* kErrHookAfterExecuteCodeGenPasses */ |
| 79 | "Error occurred during afterExecuteCodeGenPasses() in subclass.", |
Logan | 1f028c0 | 2010-11-27 01:02:48 +0800 | [diff] [blame] | 80 | |
Zonr Chang | fef9a1b | 2012-04-13 15:58:24 +0800 | [diff] [blame] | 81 | /* kMaxErrorCode */ |
| 82 | "(Unknown error code)" |
| 83 | }; |
Logan | 1f028c0 | 2010-11-27 01:02:48 +0800 | [diff] [blame] | 84 | |
Zonr Chang | fef9a1b | 2012-04-13 15:58:24 +0800 | [diff] [blame] | 85 | if (pErrCode > kMaxErrorCode) { |
| 86 | pErrCode = kMaxErrorCode; |
Shih-wei Liao | 40bcd66 | 2011-10-22 17:51:01 -0700 | [diff] [blame] | 87 | } |
| 88 | |
Zonr Chang | fef9a1b | 2012-04-13 15:58:24 +0800 | [diff] [blame] | 89 | return ErrorString[ static_cast<size_t>(pErrCode) ]; |
Logan | 1f028c0 | 2010-11-27 01:02:48 +0800 | [diff] [blame] | 90 | } |
| 91 | |
Zonr Chang | fef9a1b | 2012-04-13 15:58:24 +0800 | [diff] [blame] | 92 | //===----------------------------------------------------------------------===// |
| 93 | // Instance Methods |
| 94 | //===----------------------------------------------------------------------===// |
| 95 | Compiler::Compiler() : mTarget(NULL), mEnableLTO(true) { |
Logan | 1f028c0 | 2010-11-27 01:02:48 +0800 | [diff] [blame] | 96 | return; |
| 97 | } |
| 98 | |
Zonr Chang | fef9a1b | 2012-04-13 15:58:24 +0800 | [diff] [blame] | 99 | Compiler::Compiler(const CompilerConfig &pConfig) : mTarget(NULL), |
| 100 | mEnableLTO(true) { |
| 101 | const std::string &triple = pConfig.getTriple(); |
| 102 | |
| 103 | enum ErrorCode err = config(pConfig); |
| 104 | if (err != kSuccess) { |
| 105 | ALOGE("%s (%s, features: %s)", GetErrorString(err), |
| 106 | triple.c_str(), pConfig.getFeatureString().c_str()); |
| 107 | return; |
Logan | 1f028c0 | 2010-11-27 01:02:48 +0800 | [diff] [blame] | 108 | } |
Zonr Chang | fef9a1b | 2012-04-13 15:58:24 +0800 | [diff] [blame] | 109 | |
| 110 | return; |
Logan | 1f028c0 | 2010-11-27 01:02:48 +0800 | [diff] [blame] | 111 | } |
| 112 | |
Zonr Chang | fef9a1b | 2012-04-13 15:58:24 +0800 | [diff] [blame] | 113 | enum Compiler::ErrorCode Compiler::config(const CompilerConfig &pConfig) { |
| 114 | if (pConfig.getTarget() == NULL) { |
| 115 | return kInvalidConfigNoTarget; |
Daniel Malea | 094881f | 2011-12-14 17:39:16 -0500 | [diff] [blame] | 116 | } |
| 117 | |
Zonr Chang | fef9a1b | 2012-04-13 15:58:24 +0800 | [diff] [blame] | 118 | llvm::TargetMachine *new_target = |
| 119 | (pConfig.getTarget())->createTargetMachine(pConfig.getTriple(), |
| 120 | pConfig.getCPU(), |
| 121 | pConfig.getFeatureString(), |
| 122 | pConfig.getTargetOptions(), |
| 123 | pConfig.getRelocationModel(), |
| 124 | pConfig.getCodeModel(), |
| 125 | pConfig.getOptimizationLevel()); |
Daniel Malea | 094881f | 2011-12-14 17:39:16 -0500 | [diff] [blame] | 126 | |
Zonr Chang | fef9a1b | 2012-04-13 15:58:24 +0800 | [diff] [blame] | 127 | if (new_target == NULL) { |
| 128 | return ((mTarget != NULL) ? kErrSwitchTargetMachine : |
| 129 | kErrCreateTargetMachine); |
| 130 | } |
| 131 | |
| 132 | // Replace the old TargetMachine. |
| 133 | delete mTarget; |
| 134 | mTarget = new_target; |
| 135 | |
| 136 | // Adjust register allocation policy according to the optimization level. |
Daniel Malea | 094881f | 2011-12-14 17:39:16 -0500 | [diff] [blame] | 137 | // createFastRegisterAllocator: fast but bad quality |
| 138 | // createLinearScanRegisterAllocator: not so fast but good quality |
Zonr Chang | fef9a1b | 2012-04-13 15:58:24 +0800 | [diff] [blame] | 139 | if ((pConfig.getOptimizationLevel() == llvm::CodeGenOpt::None)) { |
| 140 | llvm::RegisterRegAlloc::setDefault(llvm::createFastRegisterAllocator); |
| 141 | } else { |
| 142 | llvm::RegisterRegAlloc::setDefault(llvm::createGreedyRegisterAllocator); |
Logan | 1f028c0 | 2010-11-27 01:02:48 +0800 | [diff] [blame] | 143 | } |
| 144 | |
Zonr Chang | fef9a1b | 2012-04-13 15:58:24 +0800 | [diff] [blame] | 145 | // Relax all machine instructions. |
| 146 | mTarget->setMCRelaxAll(true); |
Logan Chien | be81e10 | 2011-12-16 13:31:39 +0800 | [diff] [blame] | 147 | |
Zonr Chang | fef9a1b | 2012-04-13 15:58:24 +0800 | [diff] [blame] | 148 | return kSuccess; |
Logan Chien | da5e0c3 | 2011-06-13 03:47:21 +0800 | [diff] [blame] | 149 | } |
| 150 | |
Zonr Chang | fef9a1b | 2012-04-13 15:58:24 +0800 | [diff] [blame] | 151 | Compiler::~Compiler() { |
| 152 | delete mTarget; |
| 153 | } |
Logan Chien | da5e0c3 | 2011-06-13 03:47:21 +0800 | [diff] [blame] | 154 | |
Zonr Chang | fef9a1b | 2012-04-13 15:58:24 +0800 | [diff] [blame] | 155 | enum Compiler::ErrorCode Compiler::runLTO(Script &pScript) { |
| 156 | llvm::TargetData *target_data = NULL; |
Logan Chien | da5e0c3 | 2011-06-13 03:47:21 +0800 | [diff] [blame] | 157 | |
Zonr Chang | fef9a1b | 2012-04-13 15:58:24 +0800 | [diff] [blame] | 158 | // Pass manager for link-time optimization |
| 159 | llvm::PassManager lto_passes; |
Logan Chien | da5e0c3 | 2011-06-13 03:47:21 +0800 | [diff] [blame] | 160 | |
Zonr Chang | fef9a1b | 2012-04-13 15:58:24 +0800 | [diff] [blame] | 161 | // Prepare TargetData target data from Module |
| 162 | target_data = new (std::nothrow) llvm::TargetData(*mTarget->getTargetData()); |
| 163 | if (target_data == NULL) { |
| 164 | return kErrTargetDataNoMemory; |
Logan Chien | da5e0c3 | 2011-06-13 03:47:21 +0800 | [diff] [blame] | 165 | } |
| 166 | |
Zonr Chang | fef9a1b | 2012-04-13 15:58:24 +0800 | [diff] [blame] | 167 | // Add TargetData to the pass manager. |
| 168 | lto_passes.add(target_data); |
Logan Chien | da5e0c3 | 2011-06-13 03:47:21 +0800 | [diff] [blame] | 169 | |
Zonr Chang | fef9a1b | 2012-04-13 15:58:24 +0800 | [diff] [blame] | 170 | // Invokde "beforeAddLTOPasses" before adding the first pass. |
| 171 | if (!beforeAddLTOPasses(pScript, lto_passes)) { |
| 172 | return kErrHookBeforeAddLTOPasses; |
| 173 | } |
Daniel Malea | 094881f | 2011-12-14 17:39:16 -0500 | [diff] [blame] | 174 | |
Logan Chien | 4cc0033 | 2011-06-12 14:00:46 +0800 | [diff] [blame] | 175 | // We now create passes list performing LTO. These are copied from |
Zonr Chang | fef9a1b | 2012-04-13 15:58:24 +0800 | [diff] [blame] | 176 | // (including comments) llvm::PassManagerBuilder::populateLTOPassManager(). |
| 177 | // Only a subset of these LTO passes are enabled in optimization level 0 as |
| 178 | // they interfere with interactive debugging. |
| 179 | // |
| 180 | // FIXME: Figure out which passes (if any) makes sense for levels 1 and 2. |
| 181 | //if ( != llvm::CodeGenOpt::None) { |
| 182 | if (mTarget->getOptLevel() == llvm::CodeGenOpt::None) { |
| 183 | lto_passes.add(llvm::createGlobalOptimizerPass()); |
| 184 | lto_passes.add(llvm::createConstantMergePass()); |
| 185 | } else { |
Daniel Malea | 094881f | 2011-12-14 17:39:16 -0500 | [diff] [blame] | 186 | // Propagate constants at call sites into the functions they call. This |
| 187 | // opens opportunities for globalopt (and inlining) by substituting |
| 188 | // function pointers passed as arguments to direct uses of functions. |
Zonr Chang | fef9a1b | 2012-04-13 15:58:24 +0800 | [diff] [blame] | 189 | lto_passes.add(llvm::createIPSCCPPass()); |
Logan Chien | 4cc0033 | 2011-06-12 14:00:46 +0800 | [diff] [blame] | 190 | |
Daniel Malea | 094881f | 2011-12-14 17:39:16 -0500 | [diff] [blame] | 191 | // Now that we internalized some globals, see if we can hack on them! |
Zonr Chang | fef9a1b | 2012-04-13 15:58:24 +0800 | [diff] [blame] | 192 | lto_passes.add(llvm::createGlobalOptimizerPass()); |
Logan Chien | 4cc0033 | 2011-06-12 14:00:46 +0800 | [diff] [blame] | 193 | |
Daniel Malea | 094881f | 2011-12-14 17:39:16 -0500 | [diff] [blame] | 194 | // Linking modules together can lead to duplicated global constants, only |
| 195 | // keep one copy of each constant... |
Zonr Chang | fef9a1b | 2012-04-13 15:58:24 +0800 | [diff] [blame] | 196 | lto_passes.add(llvm::createConstantMergePass()); |
Logan Chien | 4cc0033 | 2011-06-12 14:00:46 +0800 | [diff] [blame] | 197 | |
Daniel Malea | 094881f | 2011-12-14 17:39:16 -0500 | [diff] [blame] | 198 | // Remove unused arguments from functions... |
Zonr Chang | fef9a1b | 2012-04-13 15:58:24 +0800 | [diff] [blame] | 199 | lto_passes.add(llvm::createDeadArgEliminationPass()); |
Logan Chien | 4cc0033 | 2011-06-12 14:00:46 +0800 | [diff] [blame] | 200 | |
Daniel Malea | 094881f | 2011-12-14 17:39:16 -0500 | [diff] [blame] | 201 | // Reduce the code after globalopt and ipsccp. Both can open up |
| 202 | // significant simplification opportunities, and both can propagate |
| 203 | // functions through function pointers. When this happens, we often have |
| 204 | // to resolve varargs calls, etc, so let instcombine do this. |
Zonr Chang | fef9a1b | 2012-04-13 15:58:24 +0800 | [diff] [blame] | 205 | lto_passes.add(llvm::createInstructionCombiningPass()); |
Logan Chien | 4cc0033 | 2011-06-12 14:00:46 +0800 | [diff] [blame] | 206 | |
Daniel Malea | 094881f | 2011-12-14 17:39:16 -0500 | [diff] [blame] | 207 | // Inline small functions |
Zonr Chang | fef9a1b | 2012-04-13 15:58:24 +0800 | [diff] [blame] | 208 | lto_passes.add(llvm::createFunctionInliningPass()); |
Logan Chien | 4cc0033 | 2011-06-12 14:00:46 +0800 | [diff] [blame] | 209 | |
Daniel Malea | 094881f | 2011-12-14 17:39:16 -0500 | [diff] [blame] | 210 | // Remove dead EH info. |
Zonr Chang | fef9a1b | 2012-04-13 15:58:24 +0800 | [diff] [blame] | 211 | lto_passes.add(llvm::createPruneEHPass()); |
Logan Chien | 4cc0033 | 2011-06-12 14:00:46 +0800 | [diff] [blame] | 212 | |
Daniel Malea | 094881f | 2011-12-14 17:39:16 -0500 | [diff] [blame] | 213 | // Internalize the globals again after inlining |
Zonr Chang | fef9a1b | 2012-04-13 15:58:24 +0800 | [diff] [blame] | 214 | lto_passes.add(llvm::createGlobalOptimizerPass()); |
Logan Chien | 4cc0033 | 2011-06-12 14:00:46 +0800 | [diff] [blame] | 215 | |
Daniel Malea | 094881f | 2011-12-14 17:39:16 -0500 | [diff] [blame] | 216 | // Remove dead functions. |
Zonr Chang | fef9a1b | 2012-04-13 15:58:24 +0800 | [diff] [blame] | 217 | lto_passes.add(llvm::createGlobalDCEPass()); |
Logan Chien | 4cc0033 | 2011-06-12 14:00:46 +0800 | [diff] [blame] | 218 | |
Daniel Malea | 094881f | 2011-12-14 17:39:16 -0500 | [diff] [blame] | 219 | // If we didn't decide to inline a function, check to see if we can |
| 220 | // transform it to pass arguments by value instead of by reference. |
Zonr Chang | fef9a1b | 2012-04-13 15:58:24 +0800 | [diff] [blame] | 221 | lto_passes.add(llvm::createArgumentPromotionPass()); |
Logan Chien | 4cc0033 | 2011-06-12 14:00:46 +0800 | [diff] [blame] | 222 | |
Daniel Malea | 094881f | 2011-12-14 17:39:16 -0500 | [diff] [blame] | 223 | // The IPO passes may leave cruft around. Clean up after them. |
Zonr Chang | fef9a1b | 2012-04-13 15:58:24 +0800 | [diff] [blame] | 224 | lto_passes.add(llvm::createInstructionCombiningPass()); |
| 225 | lto_passes.add(llvm::createJumpThreadingPass()); |
Logan Chien | 4cc0033 | 2011-06-12 14:00:46 +0800 | [diff] [blame] | 226 | |
Daniel Malea | 094881f | 2011-12-14 17:39:16 -0500 | [diff] [blame] | 227 | // Break up allocas |
Zonr Chang | fef9a1b | 2012-04-13 15:58:24 +0800 | [diff] [blame] | 228 | lto_passes.add(llvm::createScalarReplAggregatesPass()); |
Logan Chien | 4cc0033 | 2011-06-12 14:00:46 +0800 | [diff] [blame] | 229 | |
Daniel Malea | 094881f | 2011-12-14 17:39:16 -0500 | [diff] [blame] | 230 | // Run a few AA driven optimizations here and now, to cleanup the code. |
Zonr Chang | fef9a1b | 2012-04-13 15:58:24 +0800 | [diff] [blame] | 231 | lto_passes.add(llvm::createFunctionAttrsPass()); // Add nocapture. |
| 232 | lto_passes.add(llvm::createGlobalsModRefPass()); // IP alias analysis. |
Logan Chien | 4cc0033 | 2011-06-12 14:00:46 +0800 | [diff] [blame] | 233 | |
Daniel Malea | 094881f | 2011-12-14 17:39:16 -0500 | [diff] [blame] | 234 | // Hoist loop invariants. |
Zonr Chang | fef9a1b | 2012-04-13 15:58:24 +0800 | [diff] [blame] | 235 | lto_passes.add(llvm::createLICMPass()); |
Logan Chien | 4cc0033 | 2011-06-12 14:00:46 +0800 | [diff] [blame] | 236 | |
Daniel Malea | 094881f | 2011-12-14 17:39:16 -0500 | [diff] [blame] | 237 | // Remove redundancies. |
Zonr Chang | fef9a1b | 2012-04-13 15:58:24 +0800 | [diff] [blame] | 238 | lto_passes.add(llvm::createGVNPass()); |
Logan Chien | 4cc0033 | 2011-06-12 14:00:46 +0800 | [diff] [blame] | 239 | |
Daniel Malea | 094881f | 2011-12-14 17:39:16 -0500 | [diff] [blame] | 240 | // Remove dead memcpys. |
Zonr Chang | fef9a1b | 2012-04-13 15:58:24 +0800 | [diff] [blame] | 241 | lto_passes.add(llvm::createMemCpyOptPass()); |
Logan Chien | 4cc0033 | 2011-06-12 14:00:46 +0800 | [diff] [blame] | 242 | |
Daniel Malea | 094881f | 2011-12-14 17:39:16 -0500 | [diff] [blame] | 243 | // Nuke dead stores. |
Zonr Chang | fef9a1b | 2012-04-13 15:58:24 +0800 | [diff] [blame] | 244 | lto_passes.add(llvm::createDeadStoreEliminationPass()); |
Logan Chien | 4cc0033 | 2011-06-12 14:00:46 +0800 | [diff] [blame] | 245 | |
Daniel Malea | 094881f | 2011-12-14 17:39:16 -0500 | [diff] [blame] | 246 | // Cleanup and simplify the code after the scalar optimizations. |
Zonr Chang | fef9a1b | 2012-04-13 15:58:24 +0800 | [diff] [blame] | 247 | lto_passes.add(llvm::createInstructionCombiningPass()); |
Logan Chien | 4cc0033 | 2011-06-12 14:00:46 +0800 | [diff] [blame] | 248 | |
Zonr Chang | fef9a1b | 2012-04-13 15:58:24 +0800 | [diff] [blame] | 249 | lto_passes.add(llvm::createJumpThreadingPass()); |
Logan Chien | 4cc0033 | 2011-06-12 14:00:46 +0800 | [diff] [blame] | 250 | |
Daniel Malea | 094881f | 2011-12-14 17:39:16 -0500 | [diff] [blame] | 251 | // Delete basic blocks, which optimization passes may have killed. |
Zonr Chang | fef9a1b | 2012-04-13 15:58:24 +0800 | [diff] [blame] | 252 | lto_passes.add(llvm::createCFGSimplificationPass()); |
Logan Chien | 4cc0033 | 2011-06-12 14:00:46 +0800 | [diff] [blame] | 253 | |
Daniel Malea | 094881f | 2011-12-14 17:39:16 -0500 | [diff] [blame] | 254 | // Now that we have optimized the program, discard unreachable functions. |
Zonr Chang | fef9a1b | 2012-04-13 15:58:24 +0800 | [diff] [blame] | 255 | lto_passes.add(llvm::createGlobalDCEPass()); |
Daniel Malea | 094881f | 2011-12-14 17:39:16 -0500 | [diff] [blame] | 256 | } |
Logan Chien | 4cc0033 | 2011-06-12 14:00:46 +0800 | [diff] [blame] | 257 | |
Zonr Chang | fef9a1b | 2012-04-13 15:58:24 +0800 | [diff] [blame] | 258 | // Invokde "afterAddLTOPasses" after pass manager finished its |
| 259 | // construction. |
| 260 | if (!afterAddLTOPasses(pScript, lto_passes)) { |
| 261 | return kErrHookAfterAddLTOPasses; |
Daniel Malea | 094881f | 2011-12-14 17:39:16 -0500 | [diff] [blame] | 262 | } |
Daniel Malea | 094881f | 2011-12-14 17:39:16 -0500 | [diff] [blame] | 263 | |
Zonr Chang | fef9a1b | 2012-04-13 15:58:24 +0800 | [diff] [blame] | 264 | // Invokde "beforeExecuteLTOPasses" before executing the passes. |
| 265 | if (!beforeExecuteLTOPasses(pScript, lto_passes)) { |
| 266 | return kErrHookBeforeExecuteLTOPasses; |
| 267 | } |
| 268 | |
| 269 | lto_passes.run(pScript.getSource().getModule()); |
| 270 | |
| 271 | // Invokde "afterExecuteLTOPasses" before returning. |
| 272 | if (!afterExecuteLTOPasses(pScript)) { |
| 273 | return kErrHookAfterExecuteLTOPasses; |
| 274 | } |
| 275 | |
| 276 | return kSuccess; |
Logan Chien | 4cc0033 | 2011-06-12 14:00:46 +0800 | [diff] [blame] | 277 | } |
| 278 | |
Zonr Chang | fef9a1b | 2012-04-13 15:58:24 +0800 | [diff] [blame] | 279 | enum Compiler::ErrorCode Compiler::runCodeGen(Script &pScript, |
| 280 | llvm::raw_ostream &pResult) { |
| 281 | llvm::TargetData *target_data; |
| 282 | llvm::MCContext *mc_context = NULL; |
Logan Chien | 4cc0033 | 2011-06-12 14:00:46 +0800 | [diff] [blame] | 283 | |
Zonr Chang | fef9a1b | 2012-04-13 15:58:24 +0800 | [diff] [blame] | 284 | // Create pass manager for MC code generation. |
| 285 | llvm::PassManager codegen_passes; |
| 286 | |
| 287 | // Prepare TargetData target data from Module |
| 288 | target_data = new (std::nothrow) llvm::TargetData(*mTarget->getTargetData()); |
| 289 | if (target_data == NULL) { |
| 290 | return kErrTargetDataNoMemory; |
| 291 | } |
| 292 | |
| 293 | // Add TargetData to the pass manager. |
| 294 | codegen_passes.add(target_data); |
| 295 | |
| 296 | // Invokde "beforeAddCodeGenPasses" before adding the first pass. |
| 297 | if (!beforeAddCodeGenPasses(pScript, codegen_passes)) { |
| 298 | return kErrHookBeforeAddCodeGenPasses; |
| 299 | } |
| 300 | |
| 301 | // Add passes to the pass manager to emit machine code through MC layer. |
| 302 | if (mTarget->addPassesToEmitMC(codegen_passes, mc_context, pResult, |
| 303 | /* DisableVerify */false)) { |
| 304 | return kPrepareCodeGenPass; |
| 305 | } |
| 306 | |
| 307 | // Invokde "afterAddCodeGenPasses" after pass manager finished its |
| 308 | // construction. |
| 309 | if (!afterAddCodeGenPasses(pScript, codegen_passes)) { |
| 310 | return kErrHookAfterAddCodeGenPasses; |
| 311 | } |
| 312 | |
| 313 | // Invokde "beforeExecuteCodeGenPasses" before executing the passes. |
| 314 | if (!beforeExecuteCodeGenPasses(pScript, codegen_passes)) { |
| 315 | return kErrHookBeforeExecuteCodeGenPasses; |
| 316 | } |
| 317 | |
| 318 | // Execute the pass. |
| 319 | codegen_passes.run(pScript.getSource().getModule()); |
| 320 | |
| 321 | // Invokde "afterExecuteCodeGenPasses" before returning. |
| 322 | if (!afterExecuteCodeGenPasses(pScript)) { |
| 323 | return kErrHookAfterExecuteCodeGenPasses; |
| 324 | } |
| 325 | |
| 326 | return kSuccess; |
Logan Chien | da5e0c3 | 2011-06-13 03:47:21 +0800 | [diff] [blame] | 327 | } |
Logan Chien | da5e0c3 | 2011-06-13 03:47:21 +0800 | [diff] [blame] | 328 | |
Zonr Chang | fef9a1b | 2012-04-13 15:58:24 +0800 | [diff] [blame] | 329 | enum Compiler::ErrorCode Compiler::compile(Script &pScript, |
| 330 | llvm::raw_ostream &pResult) { |
| 331 | llvm::Module &module = pScript.getSource().getModule(); |
| 332 | enum ErrorCode err; |
Logan Chien | da5e0c3 | 2011-06-13 03:47:21 +0800 | [diff] [blame] | 333 | |
Zonr Chang | fef9a1b | 2012-04-13 15:58:24 +0800 | [diff] [blame] | 334 | if (mTarget == NULL) { |
| 335 | return kErrNoTargetMachine; |
| 336 | } |
| 337 | |
| 338 | // Materialize the bitcode module. |
| 339 | if (module.getMaterializer() != NULL) { |
| 340 | std::string error; |
| 341 | // A module with non-null materializer means that it is a lazy-load module. |
| 342 | // Materialize it now via invoking MaterializeAllPermanently(). This |
| 343 | // function returns false when the materialization is successful. |
| 344 | if (module.MaterializeAllPermanently(&error)) { |
| 345 | ALOGE("Failed to materialize the module `%s'! (%s)", |
| 346 | module.getModuleIdentifier().c_str(), error.c_str()); |
| 347 | return kErrMaterialization; |
| 348 | } |
| 349 | } |
| 350 | |
| 351 | if (mEnableLTO && ((err = runLTO(pScript)) != kSuccess)) { |
| 352 | return err; |
| 353 | } |
| 354 | |
| 355 | if ((err = runCodeGen(pScript, pResult)) != kSuccess) { |
| 356 | return err; |
| 357 | } |
| 358 | |
| 359 | return kSuccess; |
Logan | 1f028c0 | 2010-11-27 01:02:48 +0800 | [diff] [blame] | 360 | } |
| 361 | |
Zonr Chang | fef9a1b | 2012-04-13 15:58:24 +0800 | [diff] [blame] | 362 | enum Compiler::ErrorCode Compiler::compile(Script &pScript, |
| 363 | OutputFile &pResult) { |
| 364 | // Check the state of the specified output file. |
| 365 | if (pResult.hasError()) { |
| 366 | return kErrInvalidOutputFileState; |
| 367 | } |
Shih-wei Liao | 90cd3d1 | 2011-06-20 15:43:34 -0700 | [diff] [blame] | 368 | |
Zonr Chang | fef9a1b | 2012-04-13 15:58:24 +0800 | [diff] [blame] | 369 | // Open the output file decorated in llvm::raw_ostream. |
| 370 | llvm::raw_ostream *out = pResult.dup(); |
| 371 | if (out == NULL) { |
| 372 | return kErrPrepareOutput; |
| 373 | } |
| 374 | |
| 375 | // Delegate the request. |
| 376 | enum Compiler::ErrorCode err = compile(pScript, *out); |
| 377 | |
| 378 | // Close the output before return. |
| 379 | delete out; |
| 380 | |
| 381 | return err; |
| 382 | } |