diff options
Diffstat (limited to 'llvm/lib/ExecutionEngine')
-rw-r--r-- | llvm/lib/ExecutionEngine/CMakeLists.txt | 1 | ||||
-rw-r--r-- | llvm/lib/ExecutionEngine/ExecutionEngine.cpp | 17 | ||||
-rw-r--r-- | llvm/lib/ExecutionEngine/LLVMBuild.txt | 2 | ||||
-rw-r--r-- | llvm/lib/ExecutionEngine/MCJIT/MCJIT.h | 2 | ||||
-rw-r--r-- | llvm/lib/ExecutionEngine/Makefile | 2 | ||||
-rw-r--r-- | llvm/lib/ExecutionEngine/Orc/CMakeLists.txt | 6 | ||||
-rw-r--r-- | llvm/lib/ExecutionEngine/Orc/CloneSubModule.cpp | 112 | ||||
-rw-r--r-- | llvm/lib/ExecutionEngine/Orc/IndirectionUtils.cpp | 157 | ||||
-rw-r--r-- | llvm/lib/ExecutionEngine/Orc/LLVMBuild.txt | 22 | ||||
-rw-r--r-- | llvm/lib/ExecutionEngine/Orc/Makefile | 13 | ||||
-rw-r--r-- | llvm/lib/ExecutionEngine/Orc/OrcMCJITReplacement.cpp | 124 | ||||
-rw-r--r-- | llvm/lib/ExecutionEngine/Orc/OrcMCJITReplacement.h | 328 | ||||
-rw-r--r-- | llvm/lib/ExecutionEngine/Orc/OrcTargetSupport.cpp | 102 | ||||
-rw-r--r-- | llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp | 6 |
14 files changed, 886 insertions, 8 deletions
diff --git a/llvm/lib/ExecutionEngine/CMakeLists.txt b/llvm/lib/ExecutionEngine/CMakeLists.txt index dc2fe9bf97f..2332795fc4c 100644 --- a/llvm/lib/ExecutionEngine/CMakeLists.txt +++ b/llvm/lib/ExecutionEngine/CMakeLists.txt @@ -10,6 +10,7 @@ add_llvm_library(LLVMExecutionEngine add_subdirectory(Interpreter) add_subdirectory(MCJIT) +add_subdirectory(Orc) add_subdirectory(RuntimeDyld) if( LLVM_USE_OPROFILE ) diff --git a/llvm/lib/ExecutionEngine/ExecutionEngine.cpp b/llvm/lib/ExecutionEngine/ExecutionEngine.cpp index 32d20ea0e30..8be399e510e 100644 --- a/llvm/lib/ExecutionEngine/ExecutionEngine.cpp +++ b/llvm/lib/ExecutionEngine/ExecutionEngine.cpp @@ -46,6 +46,11 @@ ExecutionEngine *(*ExecutionEngine::MCJITCtor)( std::unique_ptr<Module> M, std::string *ErrorStr, std::unique_ptr<RTDyldMemoryManager> MCJMM, std::unique_ptr<TargetMachine> TM) = nullptr; + +ExecutionEngine *(*ExecutionEngine::OrcMCJITReplacementCtor)( + std::string *ErrorStr, std::unique_ptr<RTDyldMemoryManager> OrcJMM, + std::unique_ptr<TargetMachine> TM) = nullptr; + ExecutionEngine *(*ExecutionEngine::InterpCtor)(std::unique_ptr<Module> M, std::string *ErrorStr) =nullptr; @@ -393,6 +398,10 @@ int ExecutionEngine::runFunctionAsMain(Function *Fn, return runFunction(Fn, GVArgs).IntVal.getZExtValue(); } +EngineBuilder::EngineBuilder() { + InitEngine(); +} + EngineBuilder::EngineBuilder(std::unique_ptr<Module> M) : M(std::move(M)), MCJMM(nullptr) { InitEngine(); @@ -414,6 +423,7 @@ void EngineBuilder::InitEngine() { Options = TargetOptions(); RelocModel = Reloc::Default; CMModel = CodeModel::JITDefault; + UseOrcMCJITReplacement = false; // IR module verification is enabled by default in debug builds, and disabled // by default in release builds. @@ -456,9 +466,14 @@ ExecutionEngine *EngineBuilder::create(TargetMachine *TM) { } ExecutionEngine *EE = nullptr; - if (ExecutionEngine::MCJITCtor) + if (ExecutionEngine::OrcMCJITReplacementCtor && UseOrcMCJITReplacement) { + EE = ExecutionEngine::OrcMCJITReplacementCtor(ErrorStr, std::move(MCJMM), + std::move(TheTM)); + EE->addModule(std::move(M)); + } else if (ExecutionEngine::MCJITCtor) EE = ExecutionEngine::MCJITCtor(std::move(M), ErrorStr, std::move(MCJMM), std::move(TheTM)); + if (EE) { EE->setVerifyModules(VerifyModules); return EE; diff --git a/llvm/lib/ExecutionEngine/LLVMBuild.txt b/llvm/lib/ExecutionEngine/LLVMBuild.txt index 7d041cef843..de8918c806b 100644 --- a/llvm/lib/ExecutionEngine/LLVMBuild.txt +++ b/llvm/lib/ExecutionEngine/LLVMBuild.txt @@ -16,7 +16,7 @@ ;===------------------------------------------------------------------------===; [common] -subdirectories = Interpreter MCJIT RuntimeDyld IntelJITEvents OProfileJIT +subdirectories = Interpreter MCJIT RuntimeDyld IntelJITEvents OProfileJIT Orc [component_0] type = Library diff --git a/llvm/lib/ExecutionEngine/MCJIT/MCJIT.h b/llvm/lib/ExecutionEngine/MCJIT/MCJIT.h index f55dd60ecba..de4a8f6a60d 100644 --- a/llvm/lib/ExecutionEngine/MCJIT/MCJIT.h +++ b/llvm/lib/ExecutionEngine/MCJIT/MCJIT.h @@ -10,12 +10,12 @@ #ifndef LLVM_LIB_EXECUTIONENGINE_MCJIT_MCJIT_H #define LLVM_LIB_EXECUTIONENGINE_MCJIT_MCJIT_H -#include "ObjectBuffer.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ExecutionEngine/ExecutionEngine.h" #include "llvm/ExecutionEngine/ObjectCache.h" +#include "llvm/ExecutionEngine/ObjectMemoryBuffer.h" #include "llvm/ExecutionEngine/RuntimeDyld.h" #include "llvm/IR/Module.h" diff --git a/llvm/lib/ExecutionEngine/Makefile b/llvm/lib/ExecutionEngine/Makefile index cf714324e3b..e9a5b79ddf6 100644 --- a/llvm/lib/ExecutionEngine/Makefile +++ b/llvm/lib/ExecutionEngine/Makefile @@ -11,7 +11,7 @@ LIBRARYNAME = LLVMExecutionEngine include $(LEVEL)/Makefile.config -PARALLEL_DIRS = Interpreter MCJIT RuntimeDyld +PARALLEL_DIRS = Interpreter MCJIT Orc RuntimeDyld ifeq ($(USE_INTEL_JITEVENTS), 1) PARALLEL_DIRS += IntelJITEvents diff --git a/llvm/lib/ExecutionEngine/Orc/CMakeLists.txt b/llvm/lib/ExecutionEngine/Orc/CMakeLists.txt new file mode 100644 index 00000000000..3fadb931200 --- /dev/null +++ b/llvm/lib/ExecutionEngine/Orc/CMakeLists.txt @@ -0,0 +1,6 @@ +add_llvm_library(LLVMOrcJIT + CloneSubModule.cpp + IndirectionUtils.cpp + OrcMCJITReplacement.cpp + OrcTargetSupport.cpp + ) diff --git a/llvm/lib/ExecutionEngine/Orc/CloneSubModule.cpp b/llvm/lib/ExecutionEngine/Orc/CloneSubModule.cpp new file mode 100644 index 00000000000..54acb78153e --- /dev/null +++ b/llvm/lib/ExecutionEngine/Orc/CloneSubModule.cpp @@ -0,0 +1,112 @@ +#include "llvm/ExecutionEngine/Orc/CloneSubModule.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/GlobalVariable.h" +#include "llvm/IR/Module.h" +#include "llvm/Transforms/Utils/Cloning.h" + +using namespace llvm; + +void llvm::copyGVInitializer(GlobalVariable &New, const GlobalVariable &Orig, + ValueToValueMapTy &VMap) { + if (Orig.hasInitializer()) + New.setInitializer(MapValue(Orig.getInitializer(), VMap)); +} + +void llvm::copyFunctionBody(Function &New, const Function &Orig, + ValueToValueMapTy &VMap) { + if (!Orig.isDeclaration()) { + Function::arg_iterator DestI = New.arg_begin(); + for (Function::const_arg_iterator J = Orig.arg_begin(); J != Orig.arg_end(); + ++J) { + DestI->setName(J->getName()); + VMap[J] = DestI++; + } + + SmallVector<ReturnInst *, 8> Returns; // Ignore returns cloned. + CloneFunctionInto(&New, &Orig, VMap, /*ModuleLevelChanges=*/true, Returns); + } +} + +std::unique_ptr<Module> +llvm::CloneSubModule(const Module &M, + HandleGlobalVariableFtor HandleGlobalVariable, + HandleFunctionFtor HandleFunction, bool KeepInlineAsm) { + + ValueToValueMapTy VMap; + + // First off, we need to create the new module. + std::unique_ptr<Module> New = + llvm::make_unique<Module>(M.getModuleIdentifier(), M.getContext()); + + New->setDataLayout(M.getDataLayout()); + New->setTargetTriple(M.getTargetTriple()); + if (KeepInlineAsm) + New->setModuleInlineAsm(M.getModuleInlineAsm()); + + // Copy global variables (but not initializers, yet). + for (Module::const_global_iterator I = M.global_begin(), E = M.global_end(); + I != E; ++I) { + GlobalVariable *GV = new GlobalVariable( + *New, I->getType()->getElementType(), I->isConstant(), I->getLinkage(), + (Constant *)nullptr, I->getName(), (GlobalVariable *)nullptr, + I->getThreadLocalMode(), I->getType()->getAddressSpace()); + GV->copyAttributesFrom(I); + VMap[I] = GV; + } + + // Loop over the functions in the module, making external functions as before + for (Module::const_iterator I = M.begin(), E = M.end(); I != E; ++I) { + Function *NF = + Function::Create(cast<FunctionType>(I->getType()->getElementType()), + I->getLinkage(), I->getName(), &*New); + NF->copyAttributesFrom(I); + VMap[I] = NF; + } + + // Loop over the aliases in the module + for (Module::const_alias_iterator I = M.alias_begin(), E = M.alias_end(); + I != E; ++I) { + auto *PTy = cast<PointerType>(I->getType()); + auto *GA = + GlobalAlias::create(PTy->getElementType(), PTy->getAddressSpace(), + I->getLinkage(), I->getName(), &*New); + GA->copyAttributesFrom(I); + VMap[I] = GA; + } + + // Now that all of the things that global variable initializer can refer to + // have been created, loop through and copy the global variable referrers + // over... We also set the attributes on the global now. + for (Module::const_global_iterator I = M.global_begin(), E = M.global_end(); + I != E; ++I) { + GlobalVariable &GV = *cast<GlobalVariable>(VMap[I]); + HandleGlobalVariable(GV, *I, VMap); + } + + // Similarly, copy over function bodies now... + // + for (Module::const_iterator I = M.begin(), E = M.end(); I != E; ++I) { + Function &F = *cast<Function>(VMap[I]); + HandleFunction(F, *I, VMap); + } + + // And aliases + for (Module::const_alias_iterator I = M.alias_begin(), E = M.alias_end(); + I != E; ++I) { + GlobalAlias *GA = cast<GlobalAlias>(VMap[I]); + if (const Constant *C = I->getAliasee()) + GA->setAliasee(MapValue(C, VMap)); + } + + // And named metadata.... + for (Module::const_named_metadata_iterator I = M.named_metadata_begin(), + E = M.named_metadata_end(); + I != E; ++I) { + const NamedMDNode &NMD = *I; + NamedMDNode *NewNMD = New->getOrInsertNamedMetadata(NMD.getName()); + for (unsigned i = 0, e = NMD.getNumOperands(); i != e; ++i) + NewNMD->addOperand(MapMetadata(NMD.getOperand(i), VMap)); + } + + return New; +} diff --git a/llvm/lib/ExecutionEngine/Orc/IndirectionUtils.cpp b/llvm/lib/ExecutionEngine/Orc/IndirectionUtils.cpp new file mode 100644 index 00000000000..e75092b2485 --- /dev/null +++ b/llvm/lib/ExecutionEngine/Orc/IndirectionUtils.cpp @@ -0,0 +1,157 @@ +#include "llvm/ADT/Triple.h" +#include "llvm/ExecutionEngine/Orc/IndirectionUtils.h" +#include "llvm/ExecutionEngine/Orc/CloneSubModule.h" +#include "llvm/IR/CallSite.h" +#include "llvm/IR/IRBuilder.h" +#include <set> + +using namespace llvm; + +namespace llvm { + +JITIndirections makeCallsSingleIndirect( + Module &M, const std::function<bool(const Function &)> &ShouldIndirect, + const char *JITImplSuffix, const char *JITAddrSuffix) { + std::vector<Function *> Worklist; + std::vector<std::string> FuncNames; + + for (auto &F : M) + if (ShouldIndirect(F) && (F.user_begin() != F.user_end())) { + Worklist.push_back(&F); + FuncNames.push_back(F.getName()); + } + + for (auto *F : Worklist) { + GlobalVariable *FImplAddr = new GlobalVariable( + M, F->getType(), false, GlobalValue::ExternalLinkage, + Constant::getNullValue(F->getType()), F->getName() + JITAddrSuffix, + nullptr, GlobalValue::NotThreadLocal, 0, true); + FImplAddr->setVisibility(GlobalValue::HiddenVisibility); + + for (auto *U : F->users()) { + assert(isa<Instruction>(U) && "Cannot indirect non-instruction use"); + IRBuilder<> Builder(cast<Instruction>(U)); + U->replaceUsesOfWith(F, Builder.CreateLoad(FImplAddr)); + } + } + + return JITIndirections( + FuncNames, [=](StringRef S) -> std::string { return std::string(S); }, + [=](StringRef S) + -> std::string { return std::string(S) + JITAddrSuffix; }); +} + +JITIndirections makeCallsDoubleIndirect( + Module &M, const std::function<bool(const Function &)> &ShouldIndirect, + const char *JITImplSuffix, const char *JITAddrSuffix) { + + std::vector<Function *> Worklist; + std::vector<std::string> FuncNames; + + for (auto &F : M) + if (!F.isDeclaration() && !F.hasAvailableExternallyLinkage() && + ShouldIndirect(F)) + Worklist.push_back(&F); + + for (auto *F : Worklist) { + std::string OrigName = F->getName(); + F->setName(OrigName + JITImplSuffix); + FuncNames.push_back(OrigName); + + GlobalVariable *FImplAddr = new GlobalVariable( + M, F->getType(), false, GlobalValue::ExternalLinkage, + Constant::getNullValue(F->getType()), OrigName + JITAddrSuffix, nullptr, + GlobalValue::NotThreadLocal, 0, true); + FImplAddr->setVisibility(GlobalValue::HiddenVisibility); + + Function *FRedirect = + Function::Create(F->getFunctionType(), F->getLinkage(), OrigName, &M); + + F->replaceAllUsesWith(FRedirect); + + BasicBlock *EntryBlock = + BasicBlock::Create(M.getContext(), "entry", FRedirect); + + IRBuilder<> Builder(EntryBlock); + LoadInst *FImplLoadedAddr = Builder.CreateLoad(FImplAddr); + + std::vector<Value *> CallArgs; + for (Value &Arg : FRedirect->args()) + CallArgs.push_back(&Arg); + CallInst *Call = Builder.CreateCall(FImplLoadedAddr, CallArgs); + Call->setTailCall(); + Builder.CreateRet(Call); + } + + return JITIndirections( + FuncNames, [=](StringRef S) + -> std::string { return std::string(S) + JITImplSuffix; }, + [=](StringRef S) + -> std::string { return std::string(S) + JITAddrSuffix; }); +} + +std::vector<std::unique_ptr<Module>> +explode(const Module &OrigMod, + const std::function<bool(const Function &)> &ShouldExtract) { + + std::vector<std::unique_ptr<Module>> NewModules; + + // Split all the globals, non-indirected functions, etc. into a single module. + auto ExtractGlobalVars = [&](GlobalVariable &New, const GlobalVariable &Orig, + ValueToValueMapTy &VMap) { + copyGVInitializer(New, Orig, VMap); + if (New.getLinkage() == GlobalValue::PrivateLinkage) { + New.setLinkage(GlobalValue::ExternalLinkage); + New.setVisibility(GlobalValue::HiddenVisibility); + } + }; + + auto ExtractNonImplFunctions = + [&](Function &New, const Function &Orig, ValueToValueMapTy &VMap) { + if (!ShouldExtract(New)) + copyFunctionBody(New, Orig, VMap); + }; + + NewModules.push_back(CloneSubModule(OrigMod, ExtractGlobalVars, + ExtractNonImplFunctions, true)); + + // Preserve initializers for Common linkage vars, and make private linkage + // globals external: they are now provided by the globals module extracted + // above. + auto DropGlobalVars = [&](GlobalVariable &New, const GlobalVariable &Orig, + ValueToValueMapTy &VMap) { + if (New.getLinkage() == GlobalValue::CommonLinkage) + copyGVInitializer(New, Orig, VMap); + else if (New.getLinkage() == GlobalValue::PrivateLinkage) + New.setLinkage(GlobalValue::ExternalLinkage); + }; + + // Split each 'impl' function out in to its own module. + for (const auto &Func : OrigMod) { + if (Func.isDeclaration() || !ShouldExtract(Func)) + continue; + + auto ExtractNamedFunction = + [&](Function &New, const Function &Orig, ValueToValueMapTy &VMap) { + if (New.getName() == Func.getName()) + copyFunctionBody(New, Orig, VMap); + }; + + NewModules.push_back( + CloneSubModule(OrigMod, DropGlobalVars, ExtractNamedFunction, false)); + } + + return NewModules; +} + +std::vector<std::unique_ptr<Module>> +explode(const Module &OrigMod, const JITIndirections &Indirections) { + std::set<std::string> ImplNames; + + for (const auto &FuncName : Indirections.IndirectedNames) + ImplNames.insert(Indirections.GetImplName(FuncName)); + + return explode( + OrigMod, [&](const Function &F) { return ImplNames.count(F.getName()); }); +} +} diff --git a/llvm/lib/ExecutionEngine/Orc/LLVMBuild.txt b/llvm/lib/ExecutionEngine/Orc/LLVMBuild.txt new file mode 100644 index 00000000000..620449405b5 --- /dev/null +++ b/llvm/lib/ExecutionEngine/Orc/LLVMBuild.txt @@ -0,0 +1,22 @@ +;===- ./lib/ExecutionEngine/MCJIT/LLVMBuild.txt ----------------*- Conf -*--===; +; +; The LLVM Compiler Infrastructure +; +; This file is distributed under the University of Illinois Open Source +; License. See LICENSE.TXT for details. +; +;===------------------------------------------------------------------------===; +; +; This is an LLVMBuild description file for the components in this subdirectory. +; +; For more information on the LLVMBuild system, please see: +; +; http://llvm.org/docs/LLVMBuild.html +; +;===------------------------------------------------------------------------===; + +[component_0] +type = Library +name = OrcJIT +parent = ExecutionEngine +required_libraries = Core ExecutionEngine Object RuntimeDyld Support Target diff --git a/llvm/lib/ExecutionEngine/Orc/Makefile b/llvm/lib/ExecutionEngine/Orc/Makefile new file mode 100644 index 00000000000..ac302348ee7 --- /dev/null +++ b/llvm/lib/ExecutionEngine/Orc/Makefile @@ -0,0 +1,13 @@ +##===- lib/ExecutionEngine/OrcJIT/Makefile -----------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## + +LEVEL = ../../.. +LIBRARYNAME = LLVMOrcJIT + +include $(LEVEL)/Makefile.common diff --git a/llvm/lib/ExecutionEngine/Orc/OrcMCJITReplacement.cpp b/llvm/lib/ExecutionEngine/Orc/OrcMCJITReplacement.cpp new file mode 100644 index 00000000000..f658ab2b298 --- /dev/null +++ b/llvm/lib/ExecutionEngine/Orc/OrcMCJITReplacement.cpp @@ -0,0 +1,124 @@ +//===-------- OrcMCJITReplacement.cpp - Orc-based MCJIT replacement -------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "OrcMCJITReplacement.h" +#include "llvm/ExecutionEngine/GenericValue.h" + +namespace { + +static struct RegisterJIT { + RegisterJIT() { llvm::OrcMCJITReplacement::Register(); } +} JITRegistrator; + +extern "C" void LLVMLinkInOrcMCJITReplacement() {} +} + +namespace llvm { + +GenericValue +OrcMCJITReplacement::runFunction(Function *F, + const std::vector<GenericValue> &ArgValues) { + assert(F && "Function *F was null at entry to run()"); + + void *FPtr = getPointerToFunction(F); + assert(FPtr && "Pointer to fn's code was null after getPointerToFunction"); + FunctionType *FTy = F->getFunctionType(); + Type *RetTy = FTy->getReturnType(); + + assert((FTy->getNumParams() == ArgValues.size() || + (FTy->isVarArg() && FTy->getNumParams() <= ArgValues.size())) && + "Wrong number of arguments passed into function!"); + assert(FTy->getNumParams() == ArgValues.size() && + "This doesn't support passing arguments through varargs (yet)!"); + + // Handle some common cases first. These cases correspond to common `main' + // prototypes. + if (RetTy->isIntegerTy(32) || RetTy->isVoidTy()) { + switch (ArgValues.size()) { + case 3: + if (FTy->getParamType(0)->isIntegerTy(32) && + FTy->getParamType(1)->isPointerTy() && + FTy->getParamType(2)->isPointerTy()) { + int (*PF)(int, char **, const char **) = + (int (*)(int, char **, const char **))(intptr_t)FPtr; + + // Call the function. + GenericValue rv; + rv.IntVal = APInt(32, PF(ArgValues[0].IntVal.getZExtValue(), + (char **)GVTOP(ArgValues[1]), + (const char **)GVTOP(ArgValues[2]))); + return rv; + } + break; + case 2: + if (FTy->getParamType(0)->isIntegerTy(32) && + FTy->getParamType(1)->isPointerTy()) { + int (*PF)(int, char **) = (int (*)(int, char **))(intptr_t)FPtr; + + // Call the function. + GenericValue rv; + rv.IntVal = APInt(32, PF(ArgValues[0].IntVal.getZExtValue(), + (char **)GVTOP(ArgValues[1]))); + return rv; + } + break; + case 1: + if (FTy->getNumParams() == 1 && FTy->getParamType(0)->isIntegerTy(32)) { + GenericValue rv; + int (*PF)(int) = (int (*)(int))(intptr_t)FPtr; + rv.IntVal = APInt(32, PF(ArgValues[0].IntVal.getZExtValue())); + return rv; + } + break; + } + } + + // Handle cases where no arguments are passed first. + if (ArgValues.empty()) { + GenericValue rv; + switch (RetTy->getTypeID()) { + default: + llvm_unreachable("Unknown return type for function call!"); + case Type::IntegerTyID: { + unsigned BitWidth = cast<IntegerType>(RetTy)->getBitWidth(); + if (BitWidth == 1) + rv.IntVal = APInt(BitWidth, ((bool (*)())(intptr_t)FPtr)()); + else if (BitWidth <= 8) + rv.IntVal = APInt(BitWidth, ((char (*)())(intptr_t)FPtr)()); + else if (BitWidth <= 16) + rv.IntVal = APInt(BitWidth, ((short (*)())(intptr_t)FPtr)()); + else if (BitWidth <= 32) + rv.IntVal = APInt(BitWidth, ((int (*)())(intptr_t)FPtr)()); + else if (BitWidth <= 64) + rv.IntVal = APInt(BitWidth, ((int64_t (*)())(intptr_t)FPtr)()); + else + llvm_unreachable("Integer types > 64 bits not supported"); + return rv; + } + case Type::VoidTyID: + rv.IntVal = APInt(32, ((int (*)())(intptr_t)FPtr)()); + return rv; + case Type::FloatTyID: + rv.FloatVal = ((float (*)())(intptr_t)FPtr)(); + return rv; + case Type::DoubleTyID: + rv.DoubleVal = ((double (*)())(intptr_t)FPtr)(); + return rv; + case Type::X86_FP80TyID: + case Type::FP128TyID: + case Type::PPC_FP128TyID: + llvm_unreachable("long double not supported yet"); + case Type::PointerTyID: + return PTOGV(((void *(*)())(intptr_t)FPtr)()); + } + } + + llvm_unreachable("Full-featured argument passing not supported yet!"); +} +} diff --git a/llvm/lib/ExecutionEngine/Orc/OrcMCJITReplacement.h b/llvm/lib/ExecutionEngine/Orc/OrcMCJITReplacement.h new file mode 100644 index 00000000000..9fdf0efdd90 --- /dev/null +++ b/llvm/lib/ExecutionEngine/Orc/OrcMCJITReplacement.h @@ -0,0 +1,328 @@ +//===---- OrcMCJITReplacement.h - Orc based MCJIT replacement ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Orc based MCJIT replacement. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_EXECUTIONENGINE_ORC_ORCMCJITREPLACEMENT_H +#define LLVM_LIB_EXECUTIONENGINE_ORC_ORCMCJITREPLACEMENT_H + +#include "llvm/ExecutionEngine/ExecutionEngine.h" +#include "llvm/ExecutionEngine/Orc/CompileUtils.h" +#include "llvm/ExecutionEngine/Orc/IRCompileLayer.h" +#include "llvm/ExecutionEngine/Orc/LazyEmittingLayer.h" +#include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h" +#include "llvm/Object/Archive.h" +#include "llvm/Target/TargetSubtargetInfo.h" + +namespace llvm { + +class OrcMCJITReplacement : public ExecutionEngine { + + class ForwardingRTDyldMM : public RTDyldMemoryManager { + public: + ForwardingRTDyldMM(OrcMCJITReplacement &M) : M(M) {} + + uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment, + unsigned SectionID, + StringRef SectionName) override { + uint8_t *Addr = + M.MM->allocateCodeSection(Size, Alignment, SectionID, SectionName); + M.SectionsAllocatedSinceLastLoad.insert(Addr); + return Addr; + } + + uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment, + unsigned SectionID, StringRef SectionName, + bool IsReadOnly) override { + uint8_t *Addr = M.MM->allocateDataSection(Size, Alignment, SectionID, + SectionName, IsReadOnly); + M.SectionsAllocatedSinceLastLoad.insert(Addr); + return Addr; + } + + void reserveAllocationSpace(uintptr_t CodeSize, uintptr_t DataSizeRO, + uintptr_t DataSizeRW) override { + return M.MM->reserveAllocationSpace(CodeSize, DataSizeRO, DataSizeRW); + } + + bool needsToReserveAllocationSpace() override { + return M.MM->needsToReserveAllocationSpace(); + } + + void registerEHFrames(uint8_t *Addr, uint64_t LoadAddr, + size_t Size) override { + return M.MM->registerEHFrames(Addr, LoadAddr, Size); + } + + void deregisterEHFrames(uint8_t *Addr, uint64_t LoadAddr, + size_t Size) override { + return M.MM->deregisterEHFrames(Addr, LoadAddr, Size); + } + + uint64_t getSymbolAddress(const std::string &Name) override { + return M.getSymbolAddressWithoutMangling(Name); + } + + void *getPointerToNamedFunction(const std::string &Name, + bool AbortOnFailure = true) override { + return M.MM->getPointerToNamedFunction(Name, AbortOnFailure); + } + + void notifyObjectLoaded(ExecutionEngine *EE, + const object::ObjectFile &O) override { + return M.MM->notifyObjectLoaded(EE, O); + } + + bool finalizeMemory(std::string *ErrMsg = nullptr) override { + // Each set of objects loaded will be finalized exactly once, but since + // symbol lookup during relocation may recursively trigger the + // loading/relocation of other modules, and since we're forwarding all + // finalizeMemory calls to a single underlying memory manager, we need to + // defer forwarding the call on until all necessary objects have been + // loaded. Otherwise, during the relocation of a leaf object, we will end + // up finalizing memory, causing a crash further up the stack when we + // attempt to apply relocations to finalized memory. + // To avoid finalizing too early, look at how many objects have been + // loaded but not yet finalized. This is a bit of a hack that relies on + // the fact that we're lazily emitting object files: The only way you can + // get more than one set of objects loaded but not yet finalized is if + // they were loaded during relocation of another set. + if (M.UnfinalizedSections.size() == 1) + return M.MM->finalizeMemory(ErrMsg); + return false; + } + + private: + OrcMCJITReplacement &M; + }; + +private: + static ExecutionEngine * + createOrcMCJITReplacement(std::string *ErrorMsg, + std::unique_ptr<RTDyldMemoryManager> OrcJMM, + std::unique_ptr<llvm::TargetMachine> TM) { + return new llvm::OrcMCJITReplacement(std::move(OrcJMM), std::move(TM)); + } + +public: + static void Register() { + OrcMCJITReplacementCtor = createOrcMCJITReplacement; + } + + OrcMCJITReplacement(std::unique_ptr<RTDyldMemoryManager> MM, + std::unique_ptr<TargetMachine> TM) + : TM(std::move(TM)), MM(std::move(MM)), + Mang(this->TM->getSubtargetImpl()->getDataLayout()), + NotifyObjectLoaded(*this), NotifyFinalized(*this), + ObjectLayer(NotifyObjectLoaded, NotifyFinalized), + CompileLayer(ObjectLayer, SimpleCompiler(*this->TM)), + LazyEmitLayer(CompileLayer) { + setDataLayout(this->TM->getSubtargetImpl()->getDataLayout()); + } + + void addModule(std::unique_ptr<Module> M) { + + // If this module doesn't have a DataLayout attached then attach the + // default. + if (!M->getDataLayout()) + M->setDataLayout(getDataLayout()); + + OwnedModules.push_back(std::move(M)); + std::vector<Module *> Ms; + Ms.push_back(&*OwnedModules.back()); + LazyEmitLayer.addModuleSet(std::move(Ms), + llvm::make_unique<ForwardingRTDyldMM>(*this)); + } + + void addObjectFile(std::unique_ptr<object::ObjectFile> O) override { + std::vector<std::unique_ptr<object::ObjectFile>> Objs; + Objs.push_back(std::move(O)); + ObjectLayer.addObjectSet(std::move(Objs), + llvm::make_unique<ForwardingRTDyldMM>(*this)); + } + + void addObjectFile(object::OwningBinary<object::ObjectFile> O) override { + std::unique_ptr<object::ObjectFile> Obj; + std::unique_ptr<MemoryBuffer> Buf; + std::tie(Obj, Buf) = O.takeBinary(); + std::vector<std::unique_ptr<object::ObjectFile>> Objs; + Objs.push_back(std::move(Obj)); + ObjectLayer.addObjectSet(std::move(Objs), + llvm::make_unique<ForwardingRTDyldMM>(*this)); + } + + void addArchive(object::OwningBinary<object::Archive> A) override { + Archives.push_back(std::move(A)); + } + + uint64_t getSymbolAddress(StringRef Name) { + return getSymbolAddressWithoutMangling(Mangle(Name)); + } + + void finalizeObject() override { + // This is deprecated - Aim to remove in ExecutionEngine. + // REMOVE IF POSSIBLE - Doesn't make sense for New JIT. + } + + void mapSectionAddress(const void *LocalAddress, + uint64_t TargetAddress) override { + for (auto &P : UnfinalizedSections) + if (P.second.count(LocalAddress)) + ObjectLayer.mapSectionAddress(P.first, LocalAddress, TargetAddress); + } + + uint64_t getGlobalValueAddress(const std::string &Name) override { + return getSymbolAddress(Name); + } + + uint64_t getFunctionAddress(const std::string &Name) override { + return getSymbolAddress(Name); + } + + void *getPointerToFunction(Function *F) override { + uint64_t FAddr = getSymbolAddress(F->getName()); + return reinterpret_cast<void *>(static_cast<uintptr_t>(FAddr)); + } + + void *getPointerToNamedFunction(StringRef Name, + bool AbortOnFailure = true) override { + uint64_t Addr = getSymbolAddress(Name); + if (!Addr && AbortOnFailure) + llvm_unreachable("Missing symbol!"); + return reinterpret_cast<void *>(static_cast<uintptr_t>(Addr)); + } + + GenericValue runFunction(Function *F, + const std::vector<GenericValue> &ArgValues) override; + + void setObjectCache(ObjectCache *NewCache) override { + CompileLayer.setObjectCache(NewCache); + } + +private: + uint64_t getSymbolAddressWithoutMangling(StringRef Name) { + if (uint64_t Addr = LazyEmitLayer.getSymbolAddress(Name, false)) + return Addr; + if (uint64_t Addr = MM->getSymbolAddress(Name)) + return Addr; + if (uint64_t Addr = scanArchives(Name)) + return Addr; + + return 0; + } + + uint64_t scanArchives(StringRef Name) { + for (object::OwningBinary<object::Archive> &OB : Archives) { + object::Archive *A = OB.getBinary(); + // Look for our symbols in each Archive + object::Archive::child_iterator ChildIt = A->findSym(Name); + if (ChildIt != A->child_end()) { + // FIXME: Support nested archives? + ErrorOr<std::unique_ptr<object::Binary>> ChildBinOrErr = + ChildIt->getAsBinary(); + if (ChildBinOrErr.getError()) + continue; + std::unique_ptr<object::Binary> &ChildBin = ChildBinOrErr.get(); + if (ChildBin->isObject()) { + std::vector<std::unique_ptr<object::ObjectFile>> ObjSet; + ObjSet.push_back(std::unique_ptr<object::ObjectFile>( + static_cast<object::ObjectFile *>(ChildBin.release()))); + ObjectLayer.addObjectSet( + std::move(ObjSet), llvm::make_unique<ForwardingRTDyldMM>(*this)); + if (uint64_t Addr = ObjectLayer.getSymbolAddress(Name, true)) + return Addr; + } + } + } + return 0; + } + + class NotifyObjectLoadedT { + public: + typedef std::vector<std::unique_ptr<object::ObjectFile>> ObjListT; + typedef std::vector<std::unique_ptr<RuntimeDyld::LoadedObjectInfo>> + LoadedObjInfoListT; + + NotifyObjectLoadedT(OrcMCJITReplacement &M) : M(M) {} + + void operator()(ObjectLinkingLayerBase::ObjSetHandleT H, + const ObjListT &Objects, + const LoadedObjInfoListT &Infos) const { + M.UnfinalizedSections[H] = std::move(M.SectionsAllocatedSinceLastLoad); + M.SectionsAllocatedSinceLastLoad = {}; + assert(Objects.size() == Infos.size() && + "Incorrect number of Infos for Objects."); + for (unsigned I = 0; I < Objects.size(); ++I) + M.MM->notifyObjectLoaded(&M, *Objects[I]); + }; + + private: + OrcMCJITReplacement &M; + }; + + class NotifyFinalizedT { + public: + NotifyFinalizedT(OrcMCJITReplacement &M) : M(M) {} + void operator()(ObjectLinkingLayerBase::ObjSetHandleT H) { + M.UnfinalizedSections.erase(H); + } + + private: + OrcMCJITReplacement &M; + }; + + std::string Mangle(StringRef Name) { + std::string MangledName; + { + raw_string_ostream MangledNameStream(MangledName); + Mang.getNameWithPrefix(MangledNameStream, Name); + } + return MangledName; + } + + typedef ObjectLinkingLayer<NotifyObjectLoadedT> ObjectLayerT; + typedef IRCompileLayer<ObjectLayerT> CompileLayerT; + typedef LazyEmittingLayer<CompileLayerT> LazyEmitLayerT; + + std::unique_ptr<TargetMachine> TM; + std::unique_ptr<RTDyldMemoryManager> MM; + Mangler Mang; + + NotifyObjectLoadedT NotifyObjectLoaded; + NotifyFinalizedT NotifyFinalized; + + ObjectLayerT ObjectLayer; + CompileLayerT CompileLayer; + LazyEmitLayerT LazyEmitLayer; + + // MCJIT keeps modules alive - we need to do the same for backwards + // compatibility. + std::vector<std::unique_ptr<Module>> OwnedModules; + + // We need to store ObjLayerT::ObjSetHandles for each of the object sets + // that have been emitted but not yet finalized so that we can forward the + // mapSectionAddress calls appropriately. + typedef std::set<const void *> SectionAddrSet; + struct ObjSetHandleCompare { + bool operator()(ObjectLayerT::ObjSetHandleT H1, + ObjectLayerT::ObjSetHandleT H2) const { + return &*H1 < &*H2; + } + }; + SectionAddrSet SectionsAllocatedSinceLastLoad; + std::map<ObjectLayerT::ObjSetHandleT, SectionAddrSet, ObjSetHandleCompare> + UnfinalizedSections; + + std::vector<object::OwningBinary<object::Archive>> Archives; +}; +} + +#endif // LLVM_LIB_EXECUTIONENGINE_ORC_MCJITREPLACEMENT_H diff --git a/llvm/lib/ExecutionEngine/Orc/OrcTargetSupport.cpp b/llvm/lib/ExecutionEngine/Orc/OrcTargetSupport.cpp new file mode 100644 index 00000000000..4a83a6c0b0c --- /dev/null +++ b/llvm/lib/ExecutionEngine/Orc/OrcTargetSupport.cpp @@ -0,0 +1,102 @@ +#include "llvm/ADT/Triple.h" +#include "llvm/ExecutionEngine/Orc/IndirectionUtils.h" + +#include <array> + +using namespace llvm; + +namespace { + +const char *JITCallbackFuncName = "call_jit_for_lazy_compile"; +const char *JITCallbackIndexLabelPrefix = "jit_resolve_"; + +std::array<const char *, 12> X86GPRsToSave = {{ + "rbp", "rbx", "r12", "r13", "r14", "r15", // Callee saved. + "rdi", "rsi", "rdx", "rcx", "r8", "r9", // Int args. +}}; + +std::array<const char *, 8> X86XMMsToSave = {{ + "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7" // FP args +}}; + +template <typename OStream> unsigned saveX86Regs(OStream &OS) { + for (const auto &GPR : X86GPRsToSave) + OS << " pushq %" << GPR << "\n"; + + OS << " subq $" << (16 * X86XMMsToSave.size()) << ", %rsp\n"; + + for (unsigned i = 0; i < X86XMMsToSave.size(); ++i) + OS << " movdqu %" << X86XMMsToSave[i] << ", " + << (16 * (X86XMMsToSave.size() - i - 1)) << "(%rsp)\n"; + + return (8 * X86GPRsToSave.size()) + (16 * X86XMMsToSave.size()); +} + +template <typename OStream> void restoreX86Regs(OStream &OS) { + for (unsigned i = 0; i < X86XMMsToSave.size(); ++i) + OS << " movdqu " << (16 * i) << "(%rsp), %" + << X86XMMsToSave[(X86XMMsToSave.size() - i - 1)] << "\n"; + OS << " addq $" << (16 * X86XMMsToSave.size()) << ", %rsp\n"; + + for (unsigned i = 0; i < X86GPRsToSave.size(); ++i) + OS << " popq %" << X86GPRsToSave[X86GPRsToSave.size() - i - 1] << "\n"; +} + +uint64_t call_jit_for_fn(JITResolveCallbackHandler *J, uint64_t FuncIdx) { + return J->resolve(FuncIdx); +} +} + +namespace llvm { + +std::string getJITResolveCallbackIndexLabel(unsigned I) { + std::ostringstream LabelStream; + LabelStream << JITCallbackIndexLabelPrefix << I; + return LabelStream.str(); +} + +void insertX86CallbackAsm(Module &M, JITResolveCallbackHandler &J) { + uint64_t CallbackAddr = + static_cast<uint64_t>(reinterpret_cast<uintptr_t>(call_jit_for_fn)); + + std::ostringstream JITCallbackAsm; + Triple TT(M.getTargetTriple()); + + if (TT.getOS() == Triple::Darwin) + JITCallbackAsm << ".section __TEXT,__text,regular,pure_instructions\n" + << ".align 4, 0x90\n"; + else + JITCallbackAsm << ".text\n" + << ".align 16, 0x90\n"; + + JITCallbackAsm << "jit_object_addr:\n" + << " .quad " << &J << "\n" << JITCallbackFuncName << ":\n"; + + uint64_t ReturnAddrOffset = saveX86Regs(JITCallbackAsm); + + // Compute index, load object address, and call JIT. + JITCallbackAsm << " movq " << ReturnAddrOffset << "(%rsp), %rax\n" + << " leaq (jit_indices_start+5)(%rip), %rbx\n" + << " subq %rbx, %rax\n" + << " xorq %rdx, %rdx\n" + << " movq $5, %rbx\n" + << " divq %rbx\n" + << " movq %rax, %rsi\n" + << " leaq jit_object_addr(%rip), %rdi\n" + << " movq (%rdi), %rdi\n" + << " movabsq $" << CallbackAddr << ", %rax\n" + << " callq *%rax\n" + << " movq %rax, " << ReturnAddrOffset << "(%rsp)\n"; + + restoreX86Regs(JITCallbackAsm); + + JITCallbackAsm << " retq\n" + << "jit_indices_start:\n"; + + for (JITResolveCallbackHandler::StubIndex I = 0; I < J.getNumFuncs(); ++I) + JITCallbackAsm << getJITResolveCallbackIndexLabel(I) << ":\n" + << " callq " << JITCallbackFuncName << "\n"; + + M.appendModuleInlineAsm(JITCallbackAsm.str()); +} +} diff --git a/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp b/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp index b47b56cc0d9..fb53ba96055 100644 --- a/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp +++ b/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp @@ -449,11 +449,9 @@ void RuntimeDyldImpl::emitCommonSymbols(const ObjectFile &Obj, StringRef Name; Check(Sym.getName(Name)); - assert((GlobalSymbolTable.find(Name) == GlobalSymbolTable.end()) && - "Common symbol in global symbol table."); - // Skip common symbols already elsewhere. - if (GlobalSymbolTable.count(Name)) { + if (GlobalSymbolTable.count(Name) || + MemMgr->getSymbolAddressInLogicalDylib(Name)) { DEBUG(dbgs() << "\tSkipping already emitted common symbol '" << Name << "'\n"); continue; |