From ce2207abaf9a925b35f15ef92aaff6b301ba6d22 Mon Sep 17 00:00:00 2001 From: Lang Hames Date: Tue, 21 Jan 2020 16:28:30 -0800 Subject: [PATCH] [ORC] Add support for emulated TLS to ORCv2. This commit adds a ManglingOptions struct to IRMaterializationUnit, and replaces IRCompileLayer::CompileFunction with a new IRCompileLayer::IRCompiler class. The ManglingOptions struct defines the emulated-TLS state (via a bool member, EmulatedTLS, which is true if emulated-TLS is enabled and false otherwise). The IRCompileLayer::IRCompiler class wraps an IRCompiler (the same way that the CompileFunction typedef used to), but adds a method to return the IRCompileLayer::ManglingOptions that the compiler will use. These changes allow us to correctly determine the symbols that will be produced when a thread local global variable defined at the IR level is compiled with or without emulated TLS. This is required for ORCv2, where MaterializationUnits must declare their interface up-front. Most ORCv2 clients should not require any changes. Clients writing custom IR compilers will need to wrap their compiler in an IRCompileLayer::IRCompiler, rather than an IRCompileLayer::CompileFunction, however this should be a straightforward change (see modifications to CompileUtils.* in this patch for an example). --- .../llvm/ExecutionEngine/Orc/CompileUtils.h | 19 ++-- .../llvm/ExecutionEngine/Orc/IRCompileLayer.h | 29 ++++-- llvm/include/llvm/ExecutionEngine/Orc/LLJIT.h | 4 +- llvm/include/llvm/ExecutionEngine/Orc/Layer.h | 89 +++++++++++-------- .../llvm/ExecutionEngine/Orc/Speculation.h | 4 +- .../Orc/CompileOnDemandLayer.cpp | 39 ++++---- llvm/lib/ExecutionEngine/Orc/CompileUtils.cpp | 31 ++++--- .../ExecutionEngine/Orc/IRCompileLayer.cpp | 11 ++- .../ExecutionEngine/Orc/IRTransformLayer.cpp | 8 +- llvm/lib/ExecutionEngine/Orc/LLJIT.cpp | 6 +- llvm/lib/ExecutionEngine/Orc/Layer.cpp | 51 +++++++++-- .../ExecutionEngine/OrcLazy/emulated-tls.ll | 23 +++++ llvm/tools/lli/lli.cpp | 21 +++-- .../LegacyRTDyldObjectLinkingLayerTest.cpp | 10 +-- .../Orc/ObjectTransformLayerTest.cpp | 3 +- .../ExecutionEngine/Orc/OrcCAPITest.cpp | 4 +- .../Orc/RTDyldObjectLinkingLayerTest.cpp | 12 +-- .../Orc/RemoteObjectLayerTest.cpp | 2 +- 18 files changed, 244 insertions(+), 122 deletions(-) create mode 100644 llvm/test/ExecutionEngine/OrcLazy/emulated-tls.ll diff --git a/llvm/include/llvm/ExecutionEngine/Orc/CompileUtils.h b/llvm/include/llvm/ExecutionEngine/Orc/CompileUtils.h index eb6d84e8cbb405..218afda1b5465e 100644 --- a/llvm/include/llvm/ExecutionEngine/Orc/CompileUtils.h +++ b/llvm/include/llvm/ExecutionEngine/Orc/CompileUtils.h @@ -13,7 +13,9 @@ #ifndef LLVM_EXECUTIONENGINE_ORC_COMPILEUTILS_H #define LLVM_EXECUTIONENGINE_ORC_COMPILEUTILS_H +#include "llvm/ExecutionEngine/Orc/IRCompileLayer.h" #include "llvm/ExecutionEngine/Orc/JITTargetMachineBuilder.h" +#include "llvm/ExecutionEngine/Orc/Layer.h" #include namespace llvm { @@ -28,24 +30,31 @@ namespace orc { class JITTargetMachineBuilder; +IRMaterializationUnit::ManglingOptions +irManglingOptionsFromTargetOptions(const TargetOptions &Opts); + /// Simple compile functor: Takes a single IR module and returns an ObjectFile. /// This compiler supports a single compilation thread and LLVMContext only. /// For multithreaded compilation, use ConcurrentIRCompiler below. -class SimpleCompiler { +class SimpleCompiler : public IRCompileLayer::IRCompiler { public: using CompileResult = std::unique_ptr; /// Construct a simple compile functor with the given target. SimpleCompiler(TargetMachine &TM, ObjectCache *ObjCache = nullptr) - : TM(TM), ObjCache(ObjCache) {} + : IRCompiler(irManglingOptionsFromTargetOptions(TM.Options)), TM(TM), + ObjCache(ObjCache) {} /// Set an ObjectCache to query before compiling. void setObjectCache(ObjectCache *NewCache) { ObjCache = NewCache; } /// Compile a Module to an ObjectFile. - CompileResult operator()(Module &M); + Expected operator()(Module &M) override; private: + IRMaterializationUnit::ManglingOptions + manglingOptionsForTargetMachine(const TargetMachine &TM); + CompileResult tryToLoadFromObjectCache(const Module &M); void notifyObjectCompiled(const Module &M, const MemoryBuffer &ObjBuffer); @@ -73,14 +82,14 @@ class TMOwningSimpleCompiler : public SimpleCompiler { /// /// This class creates a new TargetMachine and SimpleCompiler instance for each /// compile. -class ConcurrentIRCompiler { +class ConcurrentIRCompiler : public IRCompileLayer::IRCompiler { public: ConcurrentIRCompiler(JITTargetMachineBuilder JTMB, ObjectCache *ObjCache = nullptr); void setObjectCache(ObjectCache *ObjCache) { this->ObjCache = ObjCache; } - std::unique_ptr operator()(Module &M); + Expected> operator()(Module &M) override; private: JITTargetMachineBuilder JTMB; diff --git a/llvm/include/llvm/ExecutionEngine/Orc/IRCompileLayer.h b/llvm/include/llvm/ExecutionEngine/Orc/IRCompileLayer.h index 52223a83ad420b..bb8270fe80a3f0 100644 --- a/llvm/include/llvm/ExecutionEngine/Orc/IRCompileLayer.h +++ b/llvm/include/llvm/ExecutionEngine/Orc/IRCompileLayer.h @@ -29,14 +29,29 @@ namespace orc { class IRCompileLayer : public IRLayer { public: - using CompileFunction = - std::function>(Module &)>; + class IRCompiler { + public: + IRCompiler(IRMaterializationUnit::ManglingOptions MO) : MO(std::move(MO)) {} + virtual ~IRCompiler(); + const IRMaterializationUnit::ManglingOptions &getManglingOptions() const { + return MO; + } + virtual Expected> operator()(Module &M) = 0; + + protected: + IRMaterializationUnit::ManglingOptions &manglingOptions() { return MO; } + + private: + IRMaterializationUnit::ManglingOptions MO; + }; using NotifyCompiledFunction = std::function; IRCompileLayer(ExecutionSession &ES, ObjectLayer &BaseLayer, - CompileFunction Compile); + std::unique_ptr Compile); + + IRCompiler &getCompiler() { return *Compile; } void setNotifyCompiled(NotifyCompiledFunction NotifyCompiled); @@ -45,7 +60,8 @@ class IRCompileLayer : public IRLayer { private: mutable std::mutex IRLayerMutex; ObjectLayer &BaseLayer; - CompileFunction Compile; + std::unique_ptr Compile; + const IRMaterializationUnit::ManglingOptions *ManglingOpts; NotifyCompiledFunction NotifyCompiled = NotifyCompiledFunction(); }; @@ -90,7 +106,10 @@ class LegacyIRCompileLayer { /// Compile the module, and add the resulting object to the base layer /// along with the given memory manager and symbol resolver. Error addModule(VModuleKey K, std::unique_ptr M) { - if (auto Err = BaseLayer.addObject(std::move(K), Compile(*M))) + auto Obj = Compile(*M); + if (!Obj) + return Obj.takeError(); + if (auto Err = BaseLayer.addObject(std::move(K), std::move(*Obj))) return Err; if (NotifyCompiled) NotifyCompiled(std::move(K), std::move(M)); diff --git a/llvm/include/llvm/ExecutionEngine/Orc/LLJIT.h b/llvm/include/llvm/ExecutionEngine/Orc/LLJIT.h index 209c598498b043..3374a29f04dff9 100644 --- a/llvm/include/llvm/ExecutionEngine/Orc/LLJIT.h +++ b/llvm/include/llvm/ExecutionEngine/Orc/LLJIT.h @@ -130,7 +130,7 @@ class LLJIT { static std::unique_ptr createObjectLinkingLayer(LLJITBuilderState &S, ExecutionSession &ES); - static Expected + static Expected> createCompileFunction(LLJITBuilderState &S, JITTargetMachineBuilder JTMB); /// Create an LLJIT instance with a single compile thread. @@ -193,7 +193,7 @@ class LLJITBuilderState { ExecutionSession &, const Triple &TT)>; using CompileFunctionCreator = - std::function( + std::function>( JITTargetMachineBuilder JTMB)>; std::unique_ptr ES; diff --git a/llvm/include/llvm/ExecutionEngine/Orc/Layer.h b/llvm/include/llvm/ExecutionEngine/Orc/Layer.h index 8f9bd704395e62..95e32b2431a05b 100644 --- a/llvm/include/llvm/ExecutionEngine/Orc/Layer.h +++ b/llvm/include/llvm/ExecutionEngine/Orc/Layer.h @@ -21,15 +21,62 @@ namespace llvm { namespace orc { +/// IRMaterializationUnit is a convenient base class for MaterializationUnits +/// wrapping LLVM IR. Represents materialization responsibility for all symbols +/// in the given module. If symbols are overridden by other definitions, then +/// their linkage is changed to available-externally. +class IRMaterializationUnit : public MaterializationUnit { +public: + struct ManglingOptions { + bool EmulatedTLS = false; + }; + + using SymbolNameToDefinitionMap = std::map; + + /// Create an IRMaterializationLayer. Scans the module to build the + /// SymbolFlags and SymbolToDefinition maps. + IRMaterializationUnit(ExecutionSession &ES, const ManglingOptions &MO, + ThreadSafeModule TSM, VModuleKey K); + + /// Create an IRMaterializationLayer from a module, and pre-existing + /// SymbolFlags and SymbolToDefinition maps. The maps must provide + /// entries for each definition in M. + /// This constructor is useful for delegating work from one + /// IRMaterializationUnit to another. + IRMaterializationUnit(ThreadSafeModule TSM, VModuleKey K, + SymbolFlagsMap SymbolFlags, + SymbolNameToDefinitionMap SymbolToDefinition); + + /// Return the ModuleIdentifier as the name for this MaterializationUnit. + StringRef getName() const override; + + const ThreadSafeModule &getModule() const { return TSM; } + +protected: + ThreadSafeModule TSM; + SymbolNameToDefinitionMap SymbolToDefinition; + +private: + void discard(const JITDylib &JD, const SymbolStringPtr &Name) override; +}; + /// Interface for layers that accept LLVM IR. class IRLayer { public: - IRLayer(ExecutionSession &ES); + IRLayer(ExecutionSession &ES, + const IRMaterializationUnit::ManglingOptions *&MO) + : ES(ES), MO(MO) {} + virtual ~IRLayer(); /// Returns the ExecutionSession for this layer. ExecutionSession &getExecutionSession() { return ES; } + /// Get the mangling options for this layer. + const IRMaterializationUnit::ManglingOptions *&getManglingOptions() const { + return MO; + } + /// Sets the CloneToNewContextOnEmit flag (false by default). /// /// When set, IR modules added to this layer will be cloned on to a new @@ -57,49 +104,15 @@ class IRLayer { private: bool CloneToNewContextOnEmit = false; ExecutionSession &ES; -}; - -/// IRMaterializationUnit is a convenient base class for MaterializationUnits -/// wrapping LLVM IR. Represents materialization responsibility for all symbols -/// in the given module. If symbols are overridden by other definitions, then -/// their linkage is changed to available-externally. -class IRMaterializationUnit : public MaterializationUnit { -public: - using SymbolNameToDefinitionMap = std::map; - - /// Create an IRMaterializationLayer. Scans the module to build the - /// SymbolFlags and SymbolToDefinition maps. - IRMaterializationUnit(ExecutionSession &ES, ThreadSafeModule TSM, - VModuleKey K); - - /// Create an IRMaterializationLayer from a module, and pre-existing - /// SymbolFlags and SymbolToDefinition maps. The maps must provide - /// entries for each definition in M. - /// This constructor is useful for delegating work from one - /// IRMaterializationUnit to another. - IRMaterializationUnit(ThreadSafeModule TSM, VModuleKey K, - SymbolFlagsMap SymbolFlags, - SymbolNameToDefinitionMap SymbolToDefinition); - - /// Return the ModuleIdentifier as the name for this MaterializationUnit. - StringRef getName() const override; - - const ThreadSafeModule &getModule() const { return TSM; } - -protected: - ThreadSafeModule TSM; - SymbolNameToDefinitionMap SymbolToDefinition; - -private: - void discard(const JITDylib &JD, const SymbolStringPtr &Name) override; + const IRMaterializationUnit::ManglingOptions *&MO; }; /// MaterializationUnit that materializes modules by calling the 'emit' method /// on the given IRLayer. class BasicIRLayerMaterializationUnit : public IRMaterializationUnit { public: - BasicIRLayerMaterializationUnit(IRLayer &L, VModuleKey K, - ThreadSafeModule TSM); + BasicIRLayerMaterializationUnit(IRLayer &L, const ManglingOptions &MO, + ThreadSafeModule TSM, VModuleKey K); private: diff --git a/llvm/include/llvm/ExecutionEngine/Orc/Speculation.h b/llvm/include/llvm/ExecutionEngine/Orc/Speculation.h index f6b86bb231678c..97a3dc365457cc 100644 --- a/llvm/include/llvm/ExecutionEngine/Orc/Speculation.h +++ b/llvm/include/llvm/ExecutionEngine/Orc/Speculation.h @@ -182,8 +182,8 @@ class IRSpeculationLayer : public IRLayer { IRSpeculationLayer(ExecutionSession &ES, IRCompileLayer &BaseLayer, Speculator &Spec, MangleAndInterner &Mangle, ResultEval Interpreter) - : IRLayer(ES), NextLayer(BaseLayer), S(Spec), Mangle(Mangle), - QueryAnalysis(Interpreter) {} + : IRLayer(ES, BaseLayer.getManglingOptions()), NextLayer(BaseLayer), + S(Spec), Mangle(Mangle), QueryAnalysis(Interpreter) {} void emit(MaterializationResponsibility R, ThreadSafeModule TSM); diff --git a/llvm/lib/ExecutionEngine/Orc/CompileOnDemandLayer.cpp b/llvm/lib/ExecutionEngine/Orc/CompileOnDemandLayer.cpp index f26835ff8a0855..9c504da611e0da 100644 --- a/llvm/lib/ExecutionEngine/Orc/CompileOnDemandLayer.cpp +++ b/llvm/lib/ExecutionEngine/Orc/CompileOnDemandLayer.cpp @@ -67,9 +67,11 @@ namespace orc { class PartitioningIRMaterializationUnit : public IRMaterializationUnit { public: - PartitioningIRMaterializationUnit(ExecutionSession &ES, ThreadSafeModule TSM, - VModuleKey K, CompileOnDemandLayer &Parent) - : IRMaterializationUnit(ES, std::move(TSM), std::move(K)), + PartitioningIRMaterializationUnit(ExecutionSession &ES, + const ManglingOptions &MO, + ThreadSafeModule TSM, VModuleKey K, + CompileOnDemandLayer &Parent) + : IRMaterializationUnit(ES, MO, std::move(TSM), std::move(K)), Parent(Parent) {} PartitioningIRMaterializationUnit( @@ -111,7 +113,8 @@ CompileOnDemandLayer::compileWholeModule(GlobalValueSet Requested) { CompileOnDemandLayer::CompileOnDemandLayer( ExecutionSession &ES, IRLayer &BaseLayer, LazyCallThroughManager &LCTMgr, IndirectStubsManagerBuilder BuildIndirectStubsManager) - : IRLayer(ES), BaseLayer(BaseLayer), LCTMgr(LCTMgr), + : IRLayer(ES, BaseLayer.getManglingOptions()), BaseLayer(BaseLayer), + LCTMgr(LCTMgr), BuildIndirectStubsManager(std::move(BuildIndirectStubsManager)) {} void CompileOnDemandLayer::setPartitionFunction(PartitionFunction Partition) { @@ -136,27 +139,23 @@ void CompileOnDemandLayer::emit(MaterializationResponsibility R, TSM.withModuleDo([&](Module &M) { // First, do some cleanup on the module: cleanUpModule(M); - - MangleAndInterner Mangle(ES, M.getDataLayout()); - for (auto &GV : M.global_values()) { - if (GV.isDeclaration() || GV.hasLocalLinkage() || - GV.hasAppendingLinkage()) - continue; - - auto Name = Mangle(GV.getName()); - auto Flags = JITSymbolFlags::fromGlobalValue(GV); - if (Flags.isCallable()) - Callables[Name] = SymbolAliasMapEntry(Name, Flags); - else - NonCallables[Name] = SymbolAliasMapEntry(Name, Flags); - } }); + for (auto &KV : R.getSymbols()) { + auto &Name = KV.first; + auto &Flags = KV.second; + if (Flags.isCallable()) + Callables[Name] = SymbolAliasMapEntry(Name, Flags); + else + NonCallables[Name] = SymbolAliasMapEntry(Name, Flags); + } + // Create a partitioning materialization unit and lodge it with the // implementation dylib. if (auto Err = PDR.getImplDylib().define( std::make_unique( - ES, std::move(TSM), R.getVModuleKey(), *this))) { + ES, *getManglingOptions(), std::move(TSM), R.getVModuleKey(), + *this))) { ES.reportError(std::move(Err)); R.failMaterialization(); return; @@ -316,7 +315,7 @@ void CompileOnDemandLayer::emitPartition( } R.replace(std::make_unique( - ES, std::move(TSM), R.getVModuleKey(), *this)); + ES, *getManglingOptions(), std::move(TSM), R.getVModuleKey(), *this)); BaseLayer.emit(std::move(R), std::move(*ExtractedTSM)); } diff --git a/llvm/lib/ExecutionEngine/Orc/CompileUtils.cpp b/llvm/lib/ExecutionEngine/Orc/CompileUtils.cpp index f5671d90420a7c..8d2c2d9c12985c 100644 --- a/llvm/lib/ExecutionEngine/Orc/CompileUtils.cpp +++ b/llvm/lib/ExecutionEngine/Orc/CompileUtils.cpp @@ -24,8 +24,17 @@ namespace llvm { namespace orc { +IRMaterializationUnit::ManglingOptions +irManglingOptionsFromTargetOptions(const TargetOptions &Opts) { + IRMaterializationUnit::ManglingOptions MO; + + MO.EmulatedTLS = Opts.EmulatedTLS; + + return MO; +} + /// Compile a Module to an ObjectFile. -SimpleCompiler::CompileResult SimpleCompiler::operator()(Module &M) { +Expected SimpleCompiler::operator()(Module &M) { CompileResult CachedObject = tryToLoadFromObjectCache(M); if (CachedObject) return CachedObject; @@ -38,7 +47,8 @@ SimpleCompiler::CompileResult SimpleCompiler::operator()(Module &M) { legacy::PassManager PM; MCContext *Ctx; if (TM.addPassesToEmitMC(PM, Ctx, ObjStream)) - llvm_unreachable("Target does not support MC emission."); + return make_error("Target does not support MC emission", + inconvertibleErrorCode()); PM.run(M); } @@ -47,14 +57,11 @@ SimpleCompiler::CompileResult SimpleCompiler::operator()(Module &M) { auto Obj = object::ObjectFile::createObjectFile(ObjBuffer->getMemBufferRef()); - if (Obj) { - notifyObjectCompiled(M, *ObjBuffer); - return std::move(ObjBuffer); - } + if (!Obj) + return Obj.takeError(); - // TODO: Actually report errors helpfully. - consumeError(Obj.takeError()); - return nullptr; + notifyObjectCompiled(M, *ObjBuffer); + return std::move(ObjBuffer); } SimpleCompiler::CompileResult @@ -73,9 +80,11 @@ void SimpleCompiler::notifyObjectCompiled(const Module &M, ConcurrentIRCompiler::ConcurrentIRCompiler(JITTargetMachineBuilder JTMB, ObjectCache *ObjCache) - : JTMB(std::move(JTMB)), ObjCache(ObjCache) {} + : IRCompiler(irManglingOptionsFromTargetOptions(JTMB.getOptions())), + JTMB(std::move(JTMB)), ObjCache(ObjCache) {} -std::unique_ptr ConcurrentIRCompiler::operator()(Module &M) { +Expected> +ConcurrentIRCompiler::operator()(Module &M) { auto TM = cantFail(JTMB.createTargetMachine()); SimpleCompiler C(*TM, ObjCache); return C(M); diff --git a/llvm/lib/ExecutionEngine/Orc/IRCompileLayer.cpp b/llvm/lib/ExecutionEngine/Orc/IRCompileLayer.cpp index d311f34179c7c0..023940dc829825 100644 --- a/llvm/lib/ExecutionEngine/Orc/IRCompileLayer.cpp +++ b/llvm/lib/ExecutionEngine/Orc/IRCompileLayer.cpp @@ -11,9 +11,14 @@ namespace llvm { namespace orc { +IRCompileLayer::IRCompiler::~IRCompiler() {} + IRCompileLayer::IRCompileLayer(ExecutionSession &ES, ObjectLayer &BaseLayer, - CompileFunction Compile) - : IRLayer(ES), BaseLayer(BaseLayer), Compile(std::move(Compile)) {} + std::unique_ptr Compile) + : IRLayer(ES, ManglingOpts), BaseLayer(BaseLayer), + Compile(std::move(Compile)) { + ManglingOpts = &this->Compile->getManglingOptions(); +} void IRCompileLayer::setNotifyCompiled(NotifyCompiledFunction NotifyCompiled) { std::lock_guard Lock(IRLayerMutex); @@ -24,7 +29,7 @@ void IRCompileLayer::emit(MaterializationResponsibility R, ThreadSafeModule TSM) { assert(TSM && "Module must not be null"); - if (auto Obj = TSM.withModuleDo(Compile)) { + if (auto Obj = TSM.withModuleDo(*Compile)) { { std::lock_guard Lock(IRLayerMutex); if (NotifyCompiled) diff --git a/llvm/lib/ExecutionEngine/Orc/IRTransformLayer.cpp b/llvm/lib/ExecutionEngine/Orc/IRTransformLayer.cpp index 845ecc71eb8708..511248f83b2592 100644 --- a/llvm/lib/ExecutionEngine/Orc/IRTransformLayer.cpp +++ b/llvm/lib/ExecutionEngine/Orc/IRTransformLayer.cpp @@ -12,10 +12,10 @@ namespace llvm { namespace orc { -IRTransformLayer::IRTransformLayer(ExecutionSession &ES, - IRLayer &BaseLayer, - TransformFunction Transform) - : IRLayer(ES), BaseLayer(BaseLayer), Transform(std::move(Transform)) {} +IRTransformLayer::IRTransformLayer(ExecutionSession &ES, IRLayer &BaseLayer, + TransformFunction Transform) + : IRLayer(ES, BaseLayer.getManglingOptions()), BaseLayer(BaseLayer), + Transform(std::move(Transform)) {} void IRTransformLayer::emit(MaterializationResponsibility R, ThreadSafeModule TSM) { diff --git a/llvm/lib/ExecutionEngine/Orc/LLJIT.cpp b/llvm/lib/ExecutionEngine/Orc/LLJIT.cpp index 4ffcade975da37..f81e584b3b2dce 100644 --- a/llvm/lib/ExecutionEngine/Orc/LLJIT.cpp +++ b/llvm/lib/ExecutionEngine/Orc/LLJIT.cpp @@ -107,7 +107,7 @@ LLJIT::createObjectLinkingLayer(LLJITBuilderState &S, ExecutionSession &ES) { return std::unique_ptr(std::move(ObjLinkingLayer)); } -Expected +Expected> LLJIT::createCompileFunction(LLJITBuilderState &S, JITTargetMachineBuilder JTMB) { @@ -118,13 +118,13 @@ LLJIT::createCompileFunction(LLJITBuilderState &S, // Otherwise default to creating a SimpleCompiler, or ConcurrentIRCompiler, // depending on the number of threads requested. if (S.NumCompileThreads > 0) - return ConcurrentIRCompiler(std::move(JTMB)); + return std::make_unique(std::move(JTMB)); auto TM = JTMB.createTargetMachine(); if (!TM) return TM.takeError(); - return TMOwningSimpleCompiler(std::move(*TM)); + return std::make_unique(std::move(*TM)); } LLJIT::LLJIT(LLJITBuilderState &S, Error &Err) diff --git a/llvm/lib/ExecutionEngine/Orc/Layer.cpp b/llvm/lib/ExecutionEngine/Orc/Layer.cpp index 580e2682ec8c60..ebc7801f11ffaa 100644 --- a/llvm/lib/ExecutionEngine/Orc/Layer.cpp +++ b/llvm/lib/ExecutionEngine/Orc/Layer.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "llvm/ExecutionEngine/Orc/Layer.h" +#include "llvm/IR/Constants.h" #include "llvm/Object/ObjectFile.h" #include "llvm/Support/Debug.h" @@ -15,15 +16,15 @@ namespace llvm { namespace orc { -IRLayer::IRLayer(ExecutionSession &ES) : ES(ES) {} IRLayer::~IRLayer() {} Error IRLayer::add(JITDylib &JD, ThreadSafeModule TSM, VModuleKey K) { return JD.define(std::make_unique( - *this, std::move(K), std::move(TSM))); + *this, *getManglingOptions(), std::move(TSM), std::move(K))); } IRMaterializationUnit::IRMaterializationUnit(ExecutionSession &ES, + const ManglingOptions &MO, ThreadSafeModule TSM, VModuleKey K) : MaterializationUnit(SymbolFlagsMap(), std::move(K)), TSM(std::move(TSM)) { @@ -32,12 +33,44 @@ IRMaterializationUnit::IRMaterializationUnit(ExecutionSession &ES, MangleAndInterner Mangle(ES, this->TSM.getModuleUnlocked()->getDataLayout()); this->TSM.withModuleDo([&](Module &M) { for (auto &G : M.global_values()) { - if (G.hasName() && !G.isDeclaration() && !G.hasLocalLinkage() && - !G.hasAvailableExternallyLinkage() && !G.hasAppendingLinkage()) { - auto MangledName = Mangle(G.getName()); - SymbolFlags[MangledName] = JITSymbolFlags::fromGlobalValue(G); - SymbolToDefinition[MangledName] = &G; + // Skip globals that don't generate symbols. + if (!G.hasName() || G.isDeclaration() || G.hasLocalLinkage() || + G.hasAvailableExternallyLinkage() || G.hasAppendingLinkage()) + continue; + + // thread locals generate different symbols depending on whether or not + // emulated TLS is enabled. + if (G.isThreadLocal() && MO.EmulatedTLS) { + auto &GV = cast(G); + + auto Flags = JITSymbolFlags::fromGlobalValue(GV); + + auto EmuTLSV = Mangle(("__emutls_v." + GV.getName()).str()); + SymbolFlags[EmuTLSV] = Flags; + SymbolToDefinition[EmuTLSV] = &GV; + + // If this GV has a non-zero initializer we'll need to emit an + // __emutls.t symbol too. + if (GV.hasInitializer()) { + const auto *InitVal = GV.getInitializer(); + + // Skip zero-initializers. + if (isa(InitVal)) + continue; + const auto *InitIntValue = dyn_cast(InitVal); + if (InitIntValue && InitIntValue->isZero()) + continue; + + auto EmuTLST = Mangle(("__emutls_t." + GV.getName()).str()); + SymbolFlags[EmuTLST] = Flags; + } + continue; } + + // Otherwise we just need a normal linker mangling. + auto MangledName = Mangle(G.getName()); + SymbolFlags[MangledName] = JITSymbolFlags::fromGlobalValue(G); + SymbolToDefinition[MangledName] = &G; } }); } @@ -72,8 +105,8 @@ void IRMaterializationUnit::discard(const JITDylib &JD, } BasicIRLayerMaterializationUnit::BasicIRLayerMaterializationUnit( - IRLayer &L, VModuleKey K, ThreadSafeModule TSM) - : IRMaterializationUnit(L.getExecutionSession(), std::move(TSM), + IRLayer &L, const ManglingOptions &MO, ThreadSafeModule TSM, VModuleKey K) + : IRMaterializationUnit(L.getExecutionSession(), MO, std::move(TSM), std::move(K)), L(L), K(std::move(K)) {} diff --git a/llvm/test/ExecutionEngine/OrcLazy/emulated-tls.ll b/llvm/test/ExecutionEngine/OrcLazy/emulated-tls.ll new file mode 100644 index 00000000000000..067052c0714ae0 --- /dev/null +++ b/llvm/test/ExecutionEngine/OrcLazy/emulated-tls.ll @@ -0,0 +1,23 @@ +; RUN: not lli -no-process-syms -emulated-tls -jit-kind=orc-lazy %s 2>&1 \ +; RUN: | FileCheck %s +; +; Test that emulated-tls does not generate any unexpected errors. +; +; Unfortunately we cannot test successful execution of JIT'd code with +; emulated-tls as this would require the JIT itself, in this case lli, to be +; built with emulated-tls, which is not a common configuration. Instead we test +; that the only error produced by the JIT for a thread-local with emulated-tls +; enabled is a missing symbol error for __emutls_get_address. An unresolved +; reference to this symbol (and only this symbol) implies (1) that the emulated +; tls lowering was applied, and (2) that thread locals defined in the JIT'd code +; were otherwise handled correctly. + +; CHECK: JIT session error: Symbols not found: [ {{[^,]*}}__emutls_get_address ] + +@x = thread_local global i32 42, align 4 + +define i32 @main(i32 %argc, i8** %argv) { +entry: + %0 = load i32, i32* @x, align 4 + ret i32 %0 +} diff --git a/llvm/tools/lli/lli.cpp b/llvm/tools/lli/lli.cpp index 89342a54eefeb3..3bf694aba17cd7 100644 --- a/llvm/tools/lli/lli.cpp +++ b/llvm/tools/lli/lli.cpp @@ -197,6 +197,11 @@ namespace { cl::desc("Generate software floating point library calls"), cl::init(false)); + cl::opt NoProcessSymbols( + "no-process-syms", + cl::desc("Do not resolve lli process symbols in JIT'd code"), + cl::init(false)); + enum class DumpKind { NoDump, DumpFuncsToStdOut, @@ -795,12 +800,16 @@ int runOrcLazyJIT(const char *ProgName) { }); orc::MangleAndInterner Mangle(J->getExecutionSession(), J->getDataLayout()); - J->getMainJITDylib().addGenerator( - ExitOnErr(orc::DynamicLibrarySearchGenerator::GetForCurrentProcess( - J->getDataLayout().getGlobalPrefix(), - [MainName = Mangle("main")](const orc::SymbolStringPtr &Name) { - return Name != MainName; - }))); + + // Unless they've been explicitly disabled, make process symbols available to + // JIT'd code. + if (!NoProcessSymbols) + J->getMainJITDylib().addGenerator( + ExitOnErr(orc::DynamicLibrarySearchGenerator::GetForCurrentProcess( + J->getDataLayout().getGlobalPrefix(), + [MainName = Mangle("main")](const orc::SymbolStringPtr &Name) { + return Name != MainName; + }))); orc::LocalCXXRuntimeOverrides CXXRuntimeOverrides; ExitOnErr(CXXRuntimeOverrides.enable(J->getMainJITDylib(), Mangle)); diff --git a/llvm/unittests/ExecutionEngine/Orc/LegacyRTDyldObjectLinkingLayerTest.cpp b/llvm/unittests/ExecutionEngine/Orc/LegacyRTDyldObjectLinkingLayerTest.cpp index 3f0f85b69a71d1..896914da624cb6 100644 --- a/llvm/unittests/ExecutionEngine/Orc/LegacyRTDyldObjectLinkingLayerTest.cpp +++ b/llvm/unittests/ExecutionEngine/Orc/LegacyRTDyldObjectLinkingLayerTest.cpp @@ -94,7 +94,7 @@ TEST(LegacyRTDyldObjectLinkingLayerTest, TestSetProcessAllSections) { if (!TM) return; - auto Obj = SimpleCompiler(*TM)(*M); + auto Obj = cantFail(SimpleCompiler(*TM)(*M)); { // Test with ProcessAllSections = false (the default). @@ -165,7 +165,7 @@ TEST_F(LegacyRTDyldObjectLinkingLayerExecutionTest, NoDuplicateFinalization) { Builder.CreateRet(FourtyTwo); } - auto Obj1 = Compile(*MB1.getModule()); + auto Obj1 = cantFail(Compile(*MB1.getModule())); ModuleBuilder MB2(Context, "", "dummy"); { @@ -178,7 +178,7 @@ TEST_F(LegacyRTDyldObjectLinkingLayerExecutionTest, NoDuplicateFinalization) { IRBuilder<> Builder(FooEntry); Builder.CreateRet(Builder.CreateCall(BarDecl)); } - auto Obj2 = Compile(*MB2.getModule()); + auto Obj2 = cantFail(Compile(*MB2.getModule())); auto K1 = ES.allocateVModule(); Resolvers[K1] = std::make_shared(); @@ -251,7 +251,7 @@ TEST_F(LegacyRTDyldObjectLinkingLayerExecutionTest, NoPrematureAllocation) { Builder.CreateRet(FourtyTwo); } - auto Obj1 = Compile(*MB1.getModule()); + auto Obj1 = cantFail(Compile(*MB1.getModule())); ModuleBuilder MB2(Context, "", "dummy"); { @@ -264,7 +264,7 @@ TEST_F(LegacyRTDyldObjectLinkingLayerExecutionTest, NoPrematureAllocation) { Value *Seven = ConstantInt::getSigned(Int32Ty, 7); Builder.CreateRet(Seven); } - auto Obj2 = Compile(*MB2.getModule()); + auto Obj2 = cantFail(Compile(*MB2.getModule())); auto K = ES.allocateVModule(); cantFail(ObjLayer.addObject(K, std::move(Obj1))); diff --git a/llvm/unittests/ExecutionEngine/Orc/ObjectTransformLayerTest.cpp b/llvm/unittests/ExecutionEngine/Orc/ObjectTransformLayerTest.cpp index 2ff7e91a732342..0d8ead53e6dae9 100644 --- a/llvm/unittests/ExecutionEngine/Orc/ObjectTransformLayerTest.cpp +++ b/llvm/unittests/ExecutionEngine/Orc/ObjectTransformLayerTest.cpp @@ -296,7 +296,8 @@ TEST(LegacyObjectTransformLayerTest, Main) { LegacyObjectTransformLayer TransformLayer(llvm::AcknowledgeORCv1Deprecation, BaseLayer, IdentityTransform); - auto NullCompiler = [](llvm::Module &) { + auto NullCompiler = [](llvm::Module &) + -> llvm::Expected> { return std::unique_ptr(nullptr); }; LegacyIRCompileLayer diff --git a/llvm/unittests/ExecutionEngine/Orc/OrcCAPITest.cpp b/llvm/unittests/ExecutionEngine/Orc/OrcCAPITest.cpp index 39fdc2e9ce9b6f..22d928cec4f2c4 100644 --- a/llvm/unittests/ExecutionEngine/Orc/OrcCAPITest.cpp +++ b/llvm/unittests/ExecutionEngine/Orc/OrcCAPITest.cpp @@ -44,7 +44,7 @@ class OrcCAPIExecutionTest : public testing::Test, public OrcExecutionTest { return MB.takeModule(); } - std::unique_ptr createTestObject() { + Expected> createTestObject() { orc::SimpleCompiler IRCompiler(*TM); auto M = createTestModule(TM->getTargetTriple()); M->setDataLayout(TM->createDataLayout()); @@ -161,7 +161,7 @@ TEST_F(OrcCAPIExecutionTest, TestAddObjectFile) { if (!SupportsJIT) return; - auto ObjBuffer = createTestObject(); + auto ObjBuffer = cantFail(createTestObject()); LLVMOrcJITStackRef JIT = LLVMOrcCreateInstance(wrap(TM.get())); diff --git a/llvm/unittests/ExecutionEngine/Orc/RTDyldObjectLinkingLayerTest.cpp b/llvm/unittests/ExecutionEngine/Orc/RTDyldObjectLinkingLayerTest.cpp index f1c0da6a9abb6c..0c66841e9af068 100644 --- a/llvm/unittests/ExecutionEngine/Orc/RTDyldObjectLinkingLayerTest.cpp +++ b/llvm/unittests/ExecutionEngine/Orc/RTDyldObjectLinkingLayerTest.cpp @@ -89,7 +89,7 @@ TEST(RTDyldObjectLinkingLayerTest, TestSetProcessAllSections) { if (!TM) return; - auto Obj = SimpleCompiler(*TM)(*M); + auto Obj = cantFail(SimpleCompiler(*TM)(*M)); EXPECT_FALSE(testSetProcessAllSections( MemoryBuffer::getMemBufferCopy(Obj->getBuffer()), false)) @@ -115,7 +115,7 @@ TEST(RTDyldObjectLinkingLayerTest, TestOverrideObjectFlags) { public: FunkySimpleCompiler(TargetMachine &TM) : SimpleCompiler(TM) {} - CompileResult operator()(Module &M) { + Expected operator()(Module &M) { auto *Foo = M.getFunction("foo"); assert(Foo && "Expected function Foo not found"); Foo->setVisibility(GlobalValue::HiddenVisibility); @@ -155,7 +155,8 @@ TEST(RTDyldObjectLinkingLayerTest, TestOverrideObjectFlags) { auto Foo = ES.intern("foo"); RTDyldObjectLinkingLayer ObjLayer( ES, []() { return std::make_unique(); }); - IRCompileLayer CompileLayer(ES, ObjLayer, FunkySimpleCompiler(*TM)); + IRCompileLayer CompileLayer(ES, ObjLayer, + std::make_unique(*TM)); ObjLayer.setOverrideObjectFlagsWithResponsibilityFlags(true); @@ -184,7 +185,7 @@ TEST(RTDyldObjectLinkingLayerTest, TestAutoClaimResponsibilityForSymbols) { public: FunkySimpleCompiler(TargetMachine &TM) : SimpleCompiler(TM) {} - CompileResult operator()(Module &M) { + Expected operator()(Module &M) { Function *BarImpl = Function::Create( FunctionType::get(Type::getVoidTy(M.getContext()), {}, false), GlobalValue::ExternalLinkage, "bar", &M); @@ -221,7 +222,8 @@ TEST(RTDyldObjectLinkingLayerTest, TestAutoClaimResponsibilityForSymbols) { auto Foo = ES.intern("foo"); RTDyldObjectLinkingLayer ObjLayer( ES, []() { return std::make_unique(); }); - IRCompileLayer CompileLayer(ES, ObjLayer, FunkySimpleCompiler(*TM)); + IRCompileLayer CompileLayer(ES, ObjLayer, + std::make_unique(*TM)); ObjLayer.setAutoClaimResponsibilityForObjectSymbols(true); diff --git a/llvm/unittests/ExecutionEngine/Orc/RemoteObjectLayerTest.cpp b/llvm/unittests/ExecutionEngine/Orc/RemoteObjectLayerTest.cpp index 4377d5267796ee..429d917237d059 100644 --- a/llvm/unittests/ExecutionEngine/Orc/RemoteObjectLayerTest.cpp +++ b/llvm/unittests/ExecutionEngine/Orc/RemoteObjectLayerTest.cpp @@ -105,7 +105,7 @@ MockObjectLayer::ObjectPtr createTestObject() { B.CreateRet(ConstantInt::getSigned(Type::getInt32Ty(Ctx), 42)); SimpleCompiler IRCompiler(*TM); - return IRCompiler(*MB.getModule()); + return cantFail(IRCompiler(*MB.getModule())); } TEST(RemoteObjectLayer, AddObject) {