/* * Copyright 2010, The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "Compiler.h" #include "Config.h" #if USE_OLD_JIT #include "OldJIT/ContextManager.h" #endif #if USE_DISASSEMBLER #include "Disassembler/Disassembler.h" #endif #include "DebugHelper.h" #include "FileHandle.h" #include "Runtime.h" #include "ScriptCompiled.h" #include "Sha1Helper.h" #if USE_MCJIT #include "librsloader.h" #endif #include "llvm/ADT/StringRef.h" #include "llvm/Analysis/Passes.h" #include "llvm/Bitcode/ReaderWriter.h" #include "llvm/CodeGen/Passes.h" #include "llvm/CodeGen/RegAllocRegistry.h" #include "llvm/CodeGen/SchedulerRegistry.h" #include "llvm/MC/SubtargetFeature.h" #include "llvm/Transforms/IPO.h" #include "llvm/Transforms/Scalar.h" #include "llvm/Target/TargetData.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetOptions.h" #include "llvm/Target/TargetRegistry.h" #include "llvm/Target/TargetSelect.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FormattedStream.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Type.h" #include "llvm/GlobalValue.h" #include "llvm/Linker.h" #include "llvm/LLVMContext.h" #include "llvm/Metadata.h" #include "llvm/Module.h" #include "llvm/PassManager.h" #include "llvm/Value.h" #include #include #include #include #include #include #include #include #include #include namespace bcc { ////////////////////////////////////////////////////////////////////////////// // BCC Compiler Static Variables ////////////////////////////////////////////////////////////////////////////// bool Compiler::GlobalInitialized = false; // Code generation optimization level for the compiler llvm::CodeGenOpt::Level Compiler::CodeGenOptLevel; std::string Compiler::Triple; std::string Compiler::CPU; std::vector Compiler::Features; // Name of metadata node where pragma info resides (should be synced with // slang.cpp) const llvm::StringRef Compiler::PragmaMetadataName = "#pragma"; // Name of metadata node where exported variable names reside (should be // synced with slang_rs_metadata.h) const llvm::StringRef Compiler::ExportVarMetadataName = "#rs_export_var"; // Name of metadata node where exported function names reside (should be // synced with slang_rs_metadata.h) const llvm::StringRef Compiler::ExportFuncMetadataName = "#rs_export_func"; // Name of metadata node where RS object slot info resides (should be // synced with slang_rs_metadata.h) const llvm::StringRef Compiler::ObjectSlotMetadataName = "#rs_object_slots"; ////////////////////////////////////////////////////////////////////////////// // Compiler ////////////////////////////////////////////////////////////////////////////// void Compiler::GlobalInitialization() { if (GlobalInitialized) return; // if (!llvm::llvm_is_multithreaded()) // llvm::llvm_start_multithreaded(); // Set Triple, CPU and Features here Triple = TARGET_TRIPLE_STRING; // NOTE: Currently, we have to turn off the support for NEON explicitly. // Since the ARMCodeEmitter.cpp is not ready for JITing NEON // instructions. #if defined(DEFAULT_ARM_CODEGEN) || defined(PROVIDE_ARM_CODEGEN) #if defined(ARCH_ARM_HAVE_VFP) Features.push_back("+vfp3"); #if !defined(ARCH_ARM_HAVE_VFP_D32) Features.push_back("+d16"); #endif #endif // FIXME - Temporarily disable NEON #if 0 && defined(ARCH_ARM_HAVE_NEON) Features.push_back("+neon"); Features.push_back("+neonfp"); #else Features.push_back("-neon"); Features.push_back("-neonfp"); #endif LLVMInitializeARMMCAsmInfo(); LLVMInitializeARMMCCodeGenInfo(); LLVMInitializeARMMCSubtargetInfo(); LLVMInitializeARMAsmPrinter(); LLVMInitializeARMTargetInfo(); LLVMInitializeARMTarget(); #endif #if defined(DEFAULT_X86_CODEGEN) || defined(PROVIDE_X86_CODEGEN) || \ defined(DEFAULT_X64_CODEGEN) || defined(PROVIDE_X64_CODEGEN) LLVMInitializeX86MCAsmInfo(); LLVMInitializeX86MCCodeGenInfo(); LLVMInitializeX86MCSubtargetInfo(); LLVMInitializeX86AsmPrinter(); LLVMInitializeX86TargetInfo(); LLVMInitializeX86Target(); #endif #if USE_DISASSEMBLER InitializeDisassembler(); #endif // -O0: llvm::CodeGenOpt::None // -O1: llvm::CodeGenOpt::Less // -O2: llvm::CodeGenOpt::Default // -O3: llvm::CodeGenOpt::Aggressive CodeGenOptLevel = llvm::CodeGenOpt::Aggressive; // Below are the global settings to LLVM // Disable frame pointer elimination optimization llvm::NoFramePointerElim = false; // Use hardfloat ABI // // TODO(all): Need to detect the CPU capability and decide whether to use // softfp. To use softfp, change following 2 lines to // // llvm::FloatABIType = llvm::FloatABI::Soft; // llvm::UseSoftFloat = true; // llvm::FloatABIType = llvm::FloatABI::Soft; llvm::UseSoftFloat = false; #if defined(DEFAULT_X64_CODEGEN) // Data address in X86_64 architecture may reside in a far-away place llvm::TargetMachine::setCodeModel(llvm::CodeModel::Medium); #else // This is set for the linker (specify how large of the virtual addresses // we can access for all unknown symbols.) llvm::TargetMachine::setCodeModel(llvm::CodeModel::Small); #endif // Register the scheduler llvm::RegisterScheduler::setDefault(llvm::createDefaultScheduler); // Register allocation policy: // createFastRegisterAllocator: fast but bad quality // createLinearScanRegisterAllocator: not so fast but good quality llvm::RegisterRegAlloc::setDefault ((CodeGenOptLevel == llvm::CodeGenOpt::None) ? llvm::createFastRegisterAllocator : llvm::createLinearScanRegisterAllocator); #if USE_CACHE // Read in SHA1 checksum of libbcc and libRS. readSHA1(sha1LibBCC_SHA1, sizeof(sha1LibBCC_SHA1), pathLibBCC_SHA1); calcFileSHA1(sha1LibRS, pathLibRS); #endif GlobalInitialized = true; } void Compiler::LLVMErrorHandler(void *UserData, const std::string &Message) { std::string *Error = static_cast(UserData); Error->assign(Message); LOGE("%s", Message.c_str()); exit(1); } #if USE_OLD_JIT CodeMemoryManager *Compiler::createCodeMemoryManager() { mCodeMemMgr.reset(new CodeMemoryManager()); return mCodeMemMgr.get(); } #endif #if USE_OLD_JIT CodeEmitter *Compiler::createCodeEmitter() { mCodeEmitter.reset(new CodeEmitter(mpResult, mCodeMemMgr.get())); return mCodeEmitter.get(); } #endif Compiler::Compiler(ScriptCompiled *result) : mpResult(result), #if USE_MCJIT mRSExecutable(NULL), #endif mpSymbolLookupFn(NULL), mpSymbolLookupContext(NULL), mContext(NULL), mModule(NULL), mHasLinked(false) /* Turn off linker */ { llvm::remove_fatal_error_handler(); llvm::install_fatal_error_handler(LLVMErrorHandler, &mError); mContext = new llvm::LLVMContext(); return; } llvm::Module *Compiler::parseBitcodeFile(llvm::MemoryBuffer *MEM) { llvm::Module *result = llvm::ParseBitcodeFile(MEM, *mContext, &mError); if (!result) { LOGE("Unable to ParseBitcodeFile: %s\n", mError.c_str()); return NULL; } return result; } int Compiler::linkModule(llvm::Module *moduleWith) { if (llvm::Linker::LinkModules(mModule, moduleWith, &mError) != 0) { return hasError(); } // Everything for linking should be settled down here with no error occurs mHasLinked = true; return hasError(); } int Compiler::compile(bool compileOnly) { llvm::Target const *Target = NULL; llvm::TargetData *TD = NULL; llvm::TargetMachine *TM = NULL; std::string FeaturesStr; llvm::NamedMDNode const *PragmaMetadata; llvm::NamedMDNode const *ExportVarMetadata; llvm::NamedMDNode const *ExportFuncMetadata; llvm::NamedMDNode const *ObjectSlotMetadata; if (mModule == NULL) // No module was loaded return 0; // Create TargetMachine Target = llvm::TargetRegistry::lookupTarget(Triple, mError); if (hasError()) goto on_bcc_compile_error; if (!CPU.empty() || !Features.empty()) { llvm::SubtargetFeatures F; for (std::vector::const_iterator I = Features.begin(), E = Features.end(); I != E; I++) { F.AddFeature(*I); } FeaturesStr = F.getString(); } TM = Target->createTargetMachine(Triple, CPU, FeaturesStr, llvm::Reloc::Static); if (TM == NULL) { setError("Failed to create target machine implementation for the" " specified triple '" + Triple + "'"); goto on_bcc_compile_error; } // Get target data from Module TD = new llvm::TargetData(mModule); // Load named metadata ExportVarMetadata = mModule->getNamedMetadata(ExportVarMetadataName); ExportFuncMetadata = mModule->getNamedMetadata(ExportFuncMetadataName); PragmaMetadata = mModule->getNamedMetadata(PragmaMetadataName); ObjectSlotMetadata = mModule->getNamedMetadata(ObjectSlotMetadataName); // Perform link-time optimization if we have multiple modules if (mHasLinked) { runLTO(new llvm::TargetData(*TD), ExportVarMetadata, ExportFuncMetadata); } // Perform code generation #if USE_OLD_JIT if (runCodeGen(new llvm::TargetData(*TD), TM, ExportVarMetadata, ExportFuncMetadata) != 0) { goto on_bcc_compile_error; } #endif #if USE_MCJIT if (runMCCodeGen(new llvm::TargetData(*TD), TM) != 0) { goto on_bcc_compile_error; } if (compileOnly) return 0; // Load the ELF Object mRSExecutable = rsloaderCreateExec((unsigned char *)&*mEmittedELFExecutable.begin(), mEmittedELFExecutable.size(), &resolveSymbolAdapter, this); if (!mRSExecutable) { setError("Fail to load emitted ELF relocatable file"); goto on_bcc_compile_error; } if (ExportVarMetadata) { ScriptCompiled::ExportVarList &varList = mpResult->mExportVars; std::vector &varNameList = mpResult->mExportVarsName; for (int i = 0, e = ExportVarMetadata->getNumOperands(); i != e; i++) { llvm::MDNode *ExportVar = ExportVarMetadata->getOperand(i); if (ExportVar != NULL && ExportVar->getNumOperands() > 1) { llvm::Value *ExportVarNameMDS = ExportVar->getOperand(0); if (ExportVarNameMDS->getValueID() == llvm::Value::MDStringVal) { llvm::StringRef ExportVarName = static_cast(ExportVarNameMDS)->getString(); varList.push_back( rsloaderGetSymbolAddress(mRSExecutable, ExportVarName.str().c_str())); varNameList.push_back(ExportVarName.str()); #if DEBUG_MCJIT_REFLECT LOGD("runMCCodeGen(): Exported Var: %s @ %p\n", ExportVarName.str().c_str(), varList.back()); #endif continue; } } varList.push_back(NULL); } } if (ExportFuncMetadata) { ScriptCompiled::ExportFuncList &funcList = mpResult->mExportFuncs; std::vector &funcNameList = mpResult->mExportFuncsName; for (int i = 0, e = ExportFuncMetadata->getNumOperands(); i != e; i++) { llvm::MDNode *ExportFunc = ExportFuncMetadata->getOperand(i); if (ExportFunc != NULL && ExportFunc->getNumOperands() > 0) { llvm::Value *ExportFuncNameMDS = ExportFunc->getOperand(0); if (ExportFuncNameMDS->getValueID() == llvm::Value::MDStringVal) { llvm::StringRef ExportFuncName = static_cast(ExportFuncNameMDS)->getString(); funcList.push_back( rsloaderGetSymbolAddress(mRSExecutable, ExportFuncName.str().c_str())); funcNameList.push_back(ExportFuncName.str()); #if DEBUG_MCJIT_RELECT LOGD("runMCCodeGen(): Exported Func: %s @ %p\n", ExportFuncName.str().c_str(), funcList.back()); #endif } } } } #if DEBUG_MCJIT_DISASSEMBLER { // Get MC codegen emitted function name list size_t func_list_size = rsloaderGetFuncCount(mRSExecutable); std::vector func_list(func_list_size, NULL); rsloaderGetFuncNameList(mRSExecutable, func_list_size, &*func_list.begin()); // Disassemble each function for (size_t i = 0; i < func_list_size; ++i) { void *func = rsloaderGetSymbolAddress(mRSExecutable, func_list[i]); if (func) { size_t size = rsloaderGetSymbolSize(mRSExecutable, func_list[i]); Disassemble(DEBUG_MCJIT_DISASSEMBLER_FILE, Target, TM, func_list[i], (unsigned char const *)func, size); } } } #endif #endif // Read pragma information from the metadata node of the module. if (PragmaMetadata) { ScriptCompiled::PragmaList &pragmaList = mpResult->mPragmas; for (int i = 0, e = PragmaMetadata->getNumOperands(); i != e; i++) { llvm::MDNode *Pragma = PragmaMetadata->getOperand(i); if (Pragma != NULL && Pragma->getNumOperands() == 2 /* should have exactly 2 operands */) { llvm::Value *PragmaNameMDS = Pragma->getOperand(0); llvm::Value *PragmaValueMDS = Pragma->getOperand(1); if ((PragmaNameMDS->getValueID() == llvm::Value::MDStringVal) && (PragmaValueMDS->getValueID() == llvm::Value::MDStringVal)) { llvm::StringRef PragmaName = static_cast(PragmaNameMDS)->getString(); llvm::StringRef PragmaValue = static_cast(PragmaValueMDS)->getString(); pragmaList.push_back( std::make_pair(std::string(PragmaName.data(), PragmaName.size()), std::string(PragmaValue.data(), PragmaValue.size()))); #if DEBUG_BCC_REFLECT LOGD("compile(): Pragma: %s -> %s\n", pragmaList.back().first.c_str(), pragmaList.back().second.c_str()); #endif } } } } if (ObjectSlotMetadata) { ScriptCompiled::ObjectSlotList &objectSlotList = mpResult->mObjectSlots; for (int i = 0, e = ObjectSlotMetadata->getNumOperands(); i != e; i++) { llvm::MDNode *ObjectSlot = ObjectSlotMetadata->getOperand(i); if (ObjectSlot != NULL && ObjectSlot->getNumOperands() == 1) { llvm::Value *SlotMDS = ObjectSlot->getOperand(0); if (SlotMDS->getValueID() == llvm::Value::MDStringVal) { llvm::StringRef Slot = static_cast(SlotMDS)->getString(); uint32_t USlot = 0; if (Slot.getAsInteger(10, USlot)) { setError("Non-integer object slot value '" + Slot.str() + "'"); goto on_bcc_compile_error; } objectSlotList.push_back(USlot); #if DEBUG_BCC_REFLECT LOGD("compile(): RefCount Slot: %s @ %u\n", Slot.str().c_str(), USlot); #endif } } } } on_bcc_compile_error: // LOGE("on_bcc_compiler_error"); if (TD) { delete TD; } if (TM) { delete TM; } if (mError.empty()) { return 0; } // LOGE(getErrorMessage()); return 1; } #if USE_OLD_JIT int Compiler::runCodeGen(llvm::TargetData *TD, llvm::TargetMachine *TM, llvm::NamedMDNode const *ExportVarMetadata, llvm::NamedMDNode const *ExportFuncMetadata) { // Create memory manager for creation of code emitter later. if (!mCodeMemMgr.get() && !createCodeMemoryManager()) { setError("Failed to startup memory management for further compilation"); return 1; } mpResult->mContext = (char *) (mCodeMemMgr.get()->getCodeMemBase()); // Create code emitter if (!mCodeEmitter.get()) { if (!createCodeEmitter()) { setError("Failed to create machine code emitter for compilation"); return 1; } } else { // Reuse the code emitter mCodeEmitter->reset(); } mCodeEmitter->setTargetMachine(*TM); mCodeEmitter->registerSymbolCallback(mpSymbolLookupFn, mpSymbolLookupContext); // Create code-gen pass to run the code emitter llvm::OwningPtr CodeGenPasses( new llvm::FunctionPassManager(mModule)); // Add TargetData to code generation pass manager CodeGenPasses->add(TD); // Add code emit passes if (TM->addPassesToEmitMachineCode(*CodeGenPasses, *mCodeEmitter, CodeGenOptLevel)) { setError("The machine code emission is not supported on '" + Triple + "'"); return 1; } // Run the code emitter on every non-declaration function in the module CodeGenPasses->doInitialization(); for (llvm::Module::iterator I = mModule->begin(), E = mModule->end(); I != E; I++) { if (!I->isDeclaration()) { CodeGenPasses->run(*I); } } CodeGenPasses->doFinalization(); // Copy the global address mapping from code emitter and remapping if (ExportVarMetadata) { ScriptCompiled::ExportVarList &varList = mpResult->mExportVars; for (int i = 0, e = ExportVarMetadata->getNumOperands(); i != e; i++) { llvm::MDNode *ExportVar = ExportVarMetadata->getOperand(i); if (ExportVar != NULL && ExportVar->getNumOperands() > 1) { llvm::Value *ExportVarNameMDS = ExportVar->getOperand(0); if (ExportVarNameMDS->getValueID() == llvm::Value::MDStringVal) { llvm::StringRef ExportVarName = static_cast(ExportVarNameMDS)->getString(); CodeEmitter::global_addresses_const_iterator I, E; for (I = mCodeEmitter->global_address_begin(), E = mCodeEmitter->global_address_end(); I != E; I++) { if (I->first->getValueID() != llvm::Value::GlobalVariableVal) continue; if (ExportVarName == I->first->getName()) { varList.push_back(I->second); #if DEBUG_BCC_REFLECT LOGD("runCodeGen(): Exported VAR: %s @ %p\n", ExportVarName.str().c_str(), I->second); #endif break; } } if (I != mCodeEmitter->global_address_end()) continue; // found #if DEBUG_BCC_REFLECT LOGD("runCodeGen(): Exported VAR: %s @ %p\n", ExportVarName.str().c_str(), (void *)0); #endif } } // if reaching here, we know the global variable record in metadata is // not found. So we make an empty slot varList.push_back(NULL); } bccAssert((varList.size() == ExportVarMetadata->getNumOperands()) && "Number of slots doesn't match the number of export variables!"); } if (ExportFuncMetadata) { ScriptCompiled::ExportFuncList &funcList = mpResult->mExportFuncs; for (int i = 0, e = ExportFuncMetadata->getNumOperands(); i != e; i++) { llvm::MDNode *ExportFunc = ExportFuncMetadata->getOperand(i); if (ExportFunc != NULL && ExportFunc->getNumOperands() > 0) { llvm::Value *ExportFuncNameMDS = ExportFunc->getOperand(0); if (ExportFuncNameMDS->getValueID() == llvm::Value::MDStringVal) { llvm::StringRef ExportFuncName = static_cast(ExportFuncNameMDS)->getString(); funcList.push_back(mpResult->lookup(ExportFuncName.str().c_str())); #if DEBUG_BCC_REFLECT LOGD("runCodeGen(): Exported Func: %s @ %p\n", ExportFuncName.str().c_str(), funcList.back()); #endif } } } } // Tell code emitter now can release the memory using during the JIT since // we have done the code emission mCodeEmitter->releaseUnnecessary(); return 0; } #endif // USE_OLD_JIT #if USE_MCJIT int Compiler::runMCCodeGen(llvm::TargetData *TD, llvm::TargetMachine *TM) { // Decorate mEmittedELFExecutable with formatted ostream llvm::raw_svector_ostream OutSVOS(mEmittedELFExecutable); // Relax all machine instructions TM->setMCRelaxAll(/* RelaxAll= */ true); // Create MC code generation pass manager llvm::PassManager MCCodeGenPasses; // Add TargetData to MC code generation pass manager MCCodeGenPasses.add(TD); // Add MC code generation passes to pass manager llvm::MCContext *Ctx; if (TM->addPassesToEmitMC(MCCodeGenPasses, Ctx, OutSVOS, CodeGenOptLevel, false)) { setError("Fail to add passes to emit file"); return 1; } MCCodeGenPasses.run(*mModule); OutSVOS.flush(); return 0; } #endif // USE_MCJIT int Compiler::runLTO(llvm::TargetData *TD, llvm::NamedMDNode const *ExportVarMetadata, llvm::NamedMDNode const *ExportFuncMetadata) { llvm::PassManager LTOPasses; // Add TargetData to LTO passes LTOPasses.add(TD); // Collect All Exported Symbols std::vector ExportSymbols; // Note: This is a workaround for getting export variable and function name. // We should refine it soon. if (ExportVarMetadata) { for (int i = 0, e = ExportVarMetadata->getNumOperands(); i != e; i++) { llvm::MDNode *ExportVar = ExportVarMetadata->getOperand(i); if (ExportVar != NULL && ExportVar->getNumOperands() > 1) { llvm::Value *ExportVarNameMDS = ExportVar->getOperand(0); if (ExportVarNameMDS->getValueID() == llvm::Value::MDStringVal) { llvm::StringRef ExportVarName = static_cast(ExportVarNameMDS)->getString(); ExportSymbols.push_back(ExportVarName.data()); } } } } if (ExportFuncMetadata) { for (int i = 0, e = ExportFuncMetadata->getNumOperands(); i != e; i++) { llvm::MDNode *ExportFunc = ExportFuncMetadata->getOperand(i); if (ExportFunc != NULL && ExportFunc->getNumOperands() > 0) { llvm::Value *ExportFuncNameMDS = ExportFunc->getOperand(0); if (ExportFuncNameMDS->getValueID() == llvm::Value::MDStringVal) { llvm::StringRef ExportFuncName = static_cast(ExportFuncNameMDS)->getString(); ExportSymbols.push_back(ExportFuncName.data()); } } } } // TODO(logan): Remove this after we have finished the // bccMarkExternalSymbol API. // root(), init(), and .rs.dtor() are born to be exported ExportSymbols.push_back("root"); ExportSymbols.push_back("init"); ExportSymbols.push_back(".rs.dtor"); // User-defined exporting symbols std::vector const &UserDefinedExternalSymbols = mpResult->getUserDefinedExternalSymbols(); std::copy(UserDefinedExternalSymbols.begin(), UserDefinedExternalSymbols.end(), std::back_inserter(ExportSymbols)); // We now create passes list performing LTO. These are copied from // (including comments) llvm::createStandardLTOPasses(). // Internalize all other symbols not listed in ExportSymbols LTOPasses.add(llvm::createInternalizePass(ExportSymbols)); // Propagate constants at call sites into the functions they call. This // opens opportunities for globalopt (and inlining) by substituting // function pointers passed as arguments to direct uses of functions. LTOPasses.add(llvm::createIPSCCPPass()); // Now that we internalized some globals, see if we can hack on them! LTOPasses.add(llvm::createGlobalOptimizerPass()); // Linking modules together can lead to duplicated global constants, only // keep one copy of each constant... LTOPasses.add(llvm::createConstantMergePass()); // Remove unused arguments from functions... LTOPasses.add(llvm::createDeadArgEliminationPass()); // Reduce the code after globalopt and ipsccp. Both can open up // significant simplification opportunities, and both can propagate // functions through function pointers. When this happens, we often have // to resolve varargs calls, etc, so let instcombine do this. LTOPasses.add(llvm::createInstructionCombiningPass()); // Inline small functions LTOPasses.add(llvm::createFunctionInliningPass()); // Remove dead EH info. LTOPasses.add(llvm::createPruneEHPass()); // Internalize the globals again after inlining LTOPasses.add(llvm::createGlobalOptimizerPass()); // Remove dead functions. LTOPasses.add(llvm::createGlobalDCEPass()); // If we didn't decide to inline a function, check to see if we can // transform it to pass arguments by value instead of by reference. LTOPasses.add(llvm::createArgumentPromotionPass()); // The IPO passes may leave cruft around. Clean up after them. LTOPasses.add(llvm::createInstructionCombiningPass()); LTOPasses.add(llvm::createJumpThreadingPass()); // Break up allocas LTOPasses.add(llvm::createScalarReplAggregatesPass()); // Run a few AA driven optimizations here and now, to cleanup the code. LTOPasses.add(llvm::createFunctionAttrsPass()); // Add nocapture. LTOPasses.add(llvm::createGlobalsModRefPass()); // IP alias analysis. // Hoist loop invariants. LTOPasses.add(llvm::createLICMPass()); // Remove redundancies. LTOPasses.add(llvm::createGVNPass()); // Remove dead memcpys. LTOPasses.add(llvm::createMemCpyOptPass()); // Nuke dead stores. LTOPasses.add(llvm::createDeadStoreEliminationPass()); // Cleanup and simplify the code after the scalar optimizations. LTOPasses.add(llvm::createInstructionCombiningPass()); LTOPasses.add(llvm::createJumpThreadingPass()); // Delete basic blocks, which optimization passes may have killed. LTOPasses.add(llvm::createCFGSimplificationPass()); // Now that we have optimized the program, discard unreachable functions. LTOPasses.add(llvm::createGlobalDCEPass()); LTOPasses.run(*mModule); return 0; } #if USE_MCJIT void *Compiler::getSymbolAddress(char const *name) { return rsloaderGetSymbolAddress(mRSExecutable, name); } #endif #if USE_MCJIT void *Compiler::resolveSymbolAdapter(void *context, char const *name) { Compiler *self = reinterpret_cast(context); if (void *Addr = FindRuntimeFunction(name)) { return Addr; } if (self->mpSymbolLookupFn) { if (void *Addr = self->mpSymbolLookupFn(self->mpSymbolLookupContext, name)) { return Addr; } } LOGE("Unable to resolve symbol: %s\n", name); return NULL; } #endif Compiler::~Compiler() { delete mModule; delete mContext; #if USE_MCJIT rsloaderDisposeExec(mRSExecutable); #endif // llvm::llvm_shutdown(); } } // namespace bcc