diff options
Diffstat (limited to 'lib/ExecutionEngine/Orc')
-rw-r--r-- | lib/ExecutionEngine/Orc/Android.mk | 18 | ||||
-rw-r--r-- | lib/ExecutionEngine/Orc/CMakeLists.txt | 9 | ||||
-rw-r--r-- | lib/ExecutionEngine/Orc/CloneSubModule.cpp | 108 | ||||
-rw-r--r-- | lib/ExecutionEngine/Orc/IndirectionUtils.cpp | 118 | ||||
-rw-r--r-- | lib/ExecutionEngine/Orc/LLVMBuild.txt | 22 | ||||
-rw-r--r-- | lib/ExecutionEngine/Orc/Makefile | 13 | ||||
-rw-r--r-- | lib/ExecutionEngine/Orc/OrcMCJITReplacement.cpp | 128 | ||||
-rw-r--r-- | lib/ExecutionEngine/Orc/OrcMCJITReplacement.h | 332 | ||||
-rw-r--r-- | lib/ExecutionEngine/Orc/OrcTargetSupport.cpp | 128 |
9 files changed, 876 insertions, 0 deletions
diff --git a/lib/ExecutionEngine/Orc/Android.mk b/lib/ExecutionEngine/Orc/Android.mk new file mode 100644 index 0000000..61c1daf --- /dev/null +++ b/lib/ExecutionEngine/Orc/Android.mk @@ -0,0 +1,18 @@ +LOCAL_PATH:= $(call my-dir) + +# For the host +# ===================================================== +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := \ + CloneSubModule.cpp \ + IndirectionUtils.cpp \ + OrcMCJITReplacement.cpp \ + OrcTargetSupport.cpp + +LOCAL_MODULE:= libLLVMOrcJIT + +LOCAL_MODULE_TAGS := optional + +include $(LLVM_HOST_BUILD_MK) +include $(BUILD_HOST_STATIC_LIBRARY) diff --git a/lib/ExecutionEngine/Orc/CMakeLists.txt b/lib/ExecutionEngine/Orc/CMakeLists.txt new file mode 100644 index 0000000..b0a8445 --- /dev/null +++ b/lib/ExecutionEngine/Orc/CMakeLists.txt @@ -0,0 +1,9 @@ +add_llvm_library(LLVMOrcJIT + CloneSubModule.cpp + IndirectionUtils.cpp + OrcMCJITReplacement.cpp + OrcTargetSupport.cpp + + ADDITIONAL_HEADER_DIRS + ${LLVM_MAIN_INCLUDE_DIR}/llvm/ExecutionEngine/Orc + ) diff --git a/lib/ExecutionEngine/Orc/CloneSubModule.cpp b/lib/ExecutionEngine/Orc/CloneSubModule.cpp new file mode 100644 index 0000000..a3196ad --- /dev/null +++ b/lib/ExecutionEngine/Orc/CloneSubModule.cpp @@ -0,0 +1,108 @@ +#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" + +namespace llvm { +namespace orc { + +void copyGVInitializer(GlobalVariable &New, const GlobalVariable &Orig, + ValueToValueMapTy &VMap) { + if (Orig.hasInitializer()) + New.setInitializer(MapValue(Orig.getInitializer(), VMap)); +} + +void 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); + } +} + +void CloneSubModule(llvm::Module &Dst, const Module &Src, + HandleGlobalVariableFtor HandleGlobalVariable, + HandleFunctionFtor HandleFunction, bool CloneInlineAsm) { + + ValueToValueMapTy VMap; + + if (CloneInlineAsm) + Dst.appendModuleInlineAsm(Src.getModuleInlineAsm()); + + // Copy global variables (but not initializers, yet). + for (Module::const_global_iterator I = Src.global_begin(), E = Src.global_end(); + I != E; ++I) { + GlobalVariable *GV = new GlobalVariable( + Dst, 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 = Src.begin(), E = Src.end(); I != E; ++I) { + Function *NF = + Function::Create(cast<FunctionType>(I->getType()->getElementType()), + I->getLinkage(), I->getName(), &Dst); + NF->copyAttributesFrom(I); + VMap[I] = NF; + } + + // Loop over the aliases in the module + for (Module::const_alias_iterator I = Src.alias_begin(), E = Src.alias_end(); + I != E; ++I) { + auto *PTy = cast<PointerType>(I->getType()); + auto *GA = + GlobalAlias::create(PTy->getElementType(), PTy->getAddressSpace(), + I->getLinkage(), I->getName(), &Dst); + 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 = Src.global_begin(), E = Src.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 = Src.begin(), E = Src.end(); I != E; ++I) { + Function &F = *cast<Function>(VMap[I]); + HandleFunction(F, *I, VMap); + } + + // And aliases + for (Module::const_alias_iterator I = Src.alias_begin(), E = Src.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 = Src.named_metadata_begin(), + E = Src.named_metadata_end(); + I != E; ++I) { + const NamedMDNode &NMD = *I; + NamedMDNode *NewNMD = Dst.getOrInsertNamedMetadata(NMD.getName()); + for (unsigned i = 0, e = NMD.getNumOperands(); i != e; ++i) + NewNMD->addOperand(MapMetadata(NMD.getOperand(i), VMap)); + } + +} + +} // End namespace orc. +} // End namespace llvm. diff --git a/lib/ExecutionEngine/Orc/IndirectionUtils.cpp b/lib/ExecutionEngine/Orc/IndirectionUtils.cpp new file mode 100644 index 0000000..61c947f --- /dev/null +++ b/lib/ExecutionEngine/Orc/IndirectionUtils.cpp @@ -0,0 +1,118 @@ +//===---- IndirectionUtils.cpp - Utilities for call indirection in Orc ----===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/Triple.h" +#include "llvm/ExecutionEngine/Orc/CloneSubModule.h" +#include "llvm/ExecutionEngine/Orc/IndirectionUtils.h" +#include "llvm/IR/CallSite.h" +#include "llvm/IR/IRBuilder.h" +#include <set> + +namespace llvm { +namespace orc { + +GlobalVariable* createImplPointer(Function &F, const Twine &Name, + Constant *Initializer) { + assert(F.getParent() && "Function isn't in a module."); + if (!Initializer) + Initializer = Constant::getNullValue(F.getType()); + Module &M = *F.getParent(); + return new GlobalVariable(M, F.getType(), false, GlobalValue::ExternalLinkage, + Initializer, Name, nullptr, + GlobalValue::NotThreadLocal, 0, true); +} + +void makeStub(Function &F, GlobalVariable &ImplPointer) { + assert(F.isDeclaration() && "Can't turn a definition into a stub."); + assert(F.getParent() && "Function isn't in a module."); + Module &M = *F.getParent(); + BasicBlock *EntryBlock = BasicBlock::Create(M.getContext(), "entry", &F); + IRBuilder<> Builder(EntryBlock); + LoadInst *ImplAddr = Builder.CreateLoad(&ImplPointer); + std::vector<Value*> CallArgs; + for (auto &A : F.args()) + CallArgs.push_back(&A); + CallInst *Call = Builder.CreateCall(ImplAddr, CallArgs); + Call->setTailCall(); + Builder.CreateRet(Call); +} + +void partition(Module &M, const ModulePartitionMap &PMap) { + + for (auto &KVPair : PMap) { + + auto ExtractGlobalVars = + [&](GlobalVariable &New, const GlobalVariable &Orig, + ValueToValueMapTy &VMap) { + if (KVPair.second.count(&Orig)) { + copyGVInitializer(New, Orig, VMap); + } + if (New.getLinkage() == GlobalValue::PrivateLinkage) { + New.setLinkage(GlobalValue::ExternalLinkage); + New.setVisibility(GlobalValue::HiddenVisibility); + } + }; + + auto ExtractFunctions = + [&](Function &New, const Function &Orig, ValueToValueMapTy &VMap) { + if (KVPair.second.count(&Orig)) + copyFunctionBody(New, Orig, VMap); + if (New.getLinkage() == GlobalValue::InternalLinkage) { + New.setLinkage(GlobalValue::ExternalLinkage); + New.setVisibility(GlobalValue::HiddenVisibility); + } + }; + + CloneSubModule(*KVPair.first, M, ExtractGlobalVars, ExtractFunctions, + false); + } +} + +FullyPartitionedModule fullyPartition(Module &M) { + FullyPartitionedModule MP; + + ModulePartitionMap PMap; + + for (auto &F : M) { + + if (F.isDeclaration()) + continue; + + std::string NewModuleName = (M.getName() + "." + F.getName()).str(); + MP.Functions.push_back( + llvm::make_unique<Module>(NewModuleName, M.getContext())); + MP.Functions.back()->setDataLayout(M.getDataLayout()); + PMap[MP.Functions.back().get()].insert(&F); + } + + MP.GlobalVars = + llvm::make_unique<Module>((M.getName() + ".globals_and_stubs").str(), + M.getContext()); + MP.GlobalVars->setDataLayout(M.getDataLayout()); + + MP.Commons = + llvm::make_unique<Module>((M.getName() + ".commons").str(), M.getContext()); + MP.Commons->setDataLayout(M.getDataLayout()); + + // Make sure there's at least an empty set for the stubs map or we'll fail + // to clone anything for it (including the decls). + PMap[MP.GlobalVars.get()] = ModulePartitionMap::mapped_type(); + for (auto &GV : M.globals()) + if (GV.getLinkage() == GlobalValue::CommonLinkage) + PMap[MP.Commons.get()].insert(&GV); + else + PMap[MP.GlobalVars.get()].insert(&GV); + + partition(M, PMap); + + return MP; +} + +} // End namespace orc. +} // End namespace llvm. diff --git a/lib/ExecutionEngine/Orc/LLVMBuild.txt b/lib/ExecutionEngine/Orc/LLVMBuild.txt new file mode 100644 index 0000000..8f05172 --- /dev/null +++ b/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 TransformUtils diff --git a/lib/ExecutionEngine/Orc/Makefile b/lib/ExecutionEngine/Orc/Makefile new file mode 100644 index 0000000..ac30234 --- /dev/null +++ b/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/lib/ExecutionEngine/Orc/OrcMCJITReplacement.cpp b/lib/ExecutionEngine/Orc/OrcMCJITReplacement.cpp new file mode 100644 index 0000000..48fd31e --- /dev/null +++ b/lib/ExecutionEngine/Orc/OrcMCJITReplacement.cpp @@ -0,0 +1,128 @@ +//===-------- 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::orc::OrcMCJITReplacement::Register(); } +} JITRegistrator; + +} + +extern "C" void LLVMLinkInOrcMCJITReplacement() {} + +namespace llvm { +namespace orc { + +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!"); +} + +} // End namespace orc. +} // End namespace llvm. diff --git a/lib/ExecutionEngine/Orc/OrcMCJITReplacement.h b/lib/ExecutionEngine/Orc/OrcMCJITReplacement.h new file mode 100644 index 0000000..1b7b161 --- /dev/null +++ b/lib/ExecutionEngine/Orc/OrcMCJITReplacement.h @@ -0,0 +1,332 @@ +//===---- 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" + +namespace llvm { +namespace orc { + +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<TargetMachine> TM) { + return new 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->getDataLayout()), + NotifyObjectLoaded(*this), NotifyFinalized(*this), + ObjectLayer(ObjectLayerT::CreateRTDyldMMFtor(), NotifyObjectLoaded, + NotifyFinalized), + CompileLayer(ObjectLayer, SimpleCompiler(*this->TM)), + LazyEmitLayer(CompileLayer) { + setDataLayout(this->TM->getDataLayout()); + } + + void addModule(std::unique_ptr<Module> M) override { + + // If this module doesn't have a DataLayout attached then attach the + // default. + if (!M->getDataLayout()) + M->setDataLayout(getDataLayout()); + + Modules.push_back(std::move(M)); + std::vector<Module *> Ms; + Ms.push_back(&*Modules.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)); + auto H = + ObjectLayer.addObjectSet(std::move(Objs), + llvm::make_unique<ForwardingRTDyldMM>(*this)); + + std::vector<std::unique_ptr<MemoryBuffer>> Bufs; + Bufs.push_back(std::move(Buf)); + ObjectLayer.takeOwnershipOfBuffers(H, std::move(Bufs)); + } + + 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.findSymbol(Name, false).getAddress()) + 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.findSymbol(Name, true).getAddress()) + 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 = SectionAddrSet(); + 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; + + // 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; +}; + +} // End namespace orc. +} // End namespace llvm. + +#endif // LLVM_LIB_EXECUTIONENGINE_ORC_MCJITREPLACEMENT_H diff --git a/lib/ExecutionEngine/Orc/OrcTargetSupport.cpp b/lib/ExecutionEngine/Orc/OrcTargetSupport.cpp new file mode 100644 index 0000000..b5dda8e --- /dev/null +++ b/lib/ExecutionEngine/Orc/OrcTargetSupport.cpp @@ -0,0 +1,128 @@ +#include "llvm/ADT/Triple.h" +#include "llvm/ExecutionEngine/Orc/OrcTargetSupport.h" +#include <array> + +using namespace llvm::orc; + +namespace { + +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"; +} + +template <typename TargetT> +uint64_t executeCompileCallback(JITCompileCallbackManagerBase<TargetT> *JCBM, + TargetAddress CallbackID) { + return JCBM->executeCompileCallback(CallbackID); +} + +} + +namespace llvm { +namespace orc { + +const char* OrcX86_64::ResolverBlockName = "orc_resolver_block"; + +void OrcX86_64::insertResolverBlock( + Module &M, JITCompileCallbackManagerBase<OrcX86_64> &JCBM) { + auto CallbackPtr = executeCompileCallback<OrcX86_64>; + uint64_t CallbackAddr = + static_cast<uint64_t>(reinterpret_cast<uintptr_t>(CallbackPtr)); + + std::ostringstream AsmStream; + Triple TT(M.getTargetTriple()); + + if (TT.getOS() == Triple::Darwin) + AsmStream << ".section __TEXT,__text,regular,pure_instructions\n" + << ".align 4, 0x90\n"; + else + AsmStream << ".text\n" + << ".align 16, 0x90\n"; + + AsmStream << "jit_callback_manager_addr:\n" + << " .quad " << &JCBM << "\n" + << ResolverBlockName << ":\n"; + + uint64_t ReturnAddrOffset = saveX86Regs(AsmStream); + + // Compute index, load object address, and call JIT. + AsmStream << " leaq jit_callback_manager_addr(%rip), %rdi\n" + << " movq (%rdi), %rdi\n" + << " movq " << ReturnAddrOffset << "(%rsp), %rsi\n" + << " movabsq $" << CallbackAddr << ", %rax\n" + << " callq *%rax\n" + << " movq %rax, " << ReturnAddrOffset << "(%rsp)\n"; + + restoreX86Regs(AsmStream); + + AsmStream << " retq\n"; + + M.appendModuleInlineAsm(AsmStream.str()); +} + +OrcX86_64::LabelNameFtor +OrcX86_64::insertCompileCallbackTrampolines(Module &M, + TargetAddress ResolverBlockAddr, + unsigned NumCalls, + unsigned StartIndex) { + const char *ResolverBlockPtrName = "Lorc_resolve_block_addr"; + + std::ostringstream AsmStream; + Triple TT(M.getTargetTriple()); + + if (TT.getOS() == Triple::Darwin) + AsmStream << ".section __TEXT,__text,regular,pure_instructions\n" + << ".align 4, 0x90\n"; + else + AsmStream << ".text\n" + << ".align 16, 0x90\n"; + + AsmStream << ResolverBlockPtrName << ":\n" + << " .quad " << ResolverBlockAddr << "\n"; + + auto GetLabelName = + [=](unsigned I) { + std::ostringstream LabelStream; + LabelStream << "orc_jcc_" << (StartIndex + I); + return LabelStream.str(); + }; + + for (unsigned I = 0; I < NumCalls; ++I) + AsmStream << GetLabelName(I) << ":\n" + << " callq *" << ResolverBlockPtrName << "(%rip)\n"; + + M.appendModuleInlineAsm(AsmStream.str()); + + return GetLabelName; +} + +} // End namespace orc. +} // End namespace llvm. |