mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-22 10:42:39 +01:00
[ORC] Add ThreadSafeModule and ThreadSafeContext wrappers to support concurrent
compilation of IR in the JIT. ThreadSafeContext is a pair of an LLVMContext and a mutex that can be used to lock that context when it needs to be accessed from multiple threads. ThreadSafeModule is a pair of a unique_ptr<Module> and a shared_ptr<ThreadSafeContext>. This allows the lifetime of a ThreadSafeContext to be managed automatically in terms of the ThreadSafeModules that refer to it: Once all modules using a ThreadSafeContext are destructed, and providing the client has not held on to a copy of shared context pointer, the context will be automatically destructed. This scheme is necessary due to the following constraits: (1) We need multiple contexts for multithreaded compilation (at least one per compile thread plus one to store any IR not currently being compiled, though one context per module is simpler). (2) We need to free contexts that are no longer being used so that the JIT does not leak memory over time. (3) Module lifetimes are not predictable (modules are compiled as needed depending on the flow of JIT'd code) so there is no single point where contexts could be reclaimed. JIT clients not using concurrency can safely use one ThreadSafeContext for all ThreadSafeModules. JIT clients who want to be able to compile concurrently should use a different ThreadSafeContext for each module, or call setCloneToNewContextOnEmit on their top-level IRLayer. The former reduces compile latency (since no clone step is needed) at the cost of additional memory overhead for uncompiled modules (as every uncompiled module will duplicate the LLVM types, constants and metadata that have been shared). llvm-svn: 343055
This commit is contained in:
parent
0bb50c0ba6
commit
7d9758f33a
@ -68,17 +68,14 @@ public:
|
|||||||
using IndirectStubsManagerBuilder =
|
using IndirectStubsManagerBuilder =
|
||||||
std::function<std::unique_ptr<IndirectStubsManager>()>;
|
std::function<std::unique_ptr<IndirectStubsManager>()>;
|
||||||
|
|
||||||
using GetAvailableContextFunction = std::function<LLVMContext &()>;
|
|
||||||
|
|
||||||
CompileOnDemandLayer2(ExecutionSession &ES, IRLayer &BaseLayer,
|
CompileOnDemandLayer2(ExecutionSession &ES, IRLayer &BaseLayer,
|
||||||
JITCompileCallbackManager &CCMgr,
|
JITCompileCallbackManager &CCMgr,
|
||||||
IndirectStubsManagerBuilder BuildIndirectStubsManager,
|
IndirectStubsManagerBuilder BuildIndirectStubsManager);
|
||||||
GetAvailableContextFunction GetAvailableContext);
|
|
||||||
|
|
||||||
Error add(JITDylib &V, VModuleKey K, std::unique_ptr<Module> M) override;
|
Error add(JITDylib &V, VModuleKey K, ThreadSafeModule TSM) override;
|
||||||
|
|
||||||
void emit(MaterializationResponsibility R, VModuleKey K,
|
void emit(MaterializationResponsibility R, VModuleKey K,
|
||||||
std::unique_ptr<Module> M) override;
|
ThreadSafeModule TSM) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
using StubManagersMap =
|
using StubManagersMap =
|
||||||
@ -87,7 +84,7 @@ private:
|
|||||||
IndirectStubsManager &getStubsManager(const JITDylib &JD);
|
IndirectStubsManager &getStubsManager(const JITDylib &JD);
|
||||||
|
|
||||||
void emitExtractedFunctionsModule(MaterializationResponsibility R,
|
void emitExtractedFunctionsModule(MaterializationResponsibility R,
|
||||||
std::unique_ptr<Module> M);
|
ThreadSafeModule TSM);
|
||||||
|
|
||||||
mutable std::mutex CODLayerMutex;
|
mutable std::mutex CODLayerMutex;
|
||||||
|
|
||||||
@ -95,7 +92,6 @@ private:
|
|||||||
JITCompileCallbackManager &CCMgr;
|
JITCompileCallbackManager &CCMgr;
|
||||||
IndirectStubsManagerBuilder BuildIndirectStubsManager;
|
IndirectStubsManagerBuilder BuildIndirectStubsManager;
|
||||||
StubManagersMap StubsMgrs;
|
StubManagersMap StubsMgrs;
|
||||||
GetAvailableContextFunction GetAvailableContext;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Compile-on-demand layer.
|
/// Compile-on-demand layer.
|
||||||
|
@ -34,7 +34,7 @@ public:
|
|||||||
std::function<Expected<std::unique_ptr<MemoryBuffer>>(Module &)>;
|
std::function<Expected<std::unique_ptr<MemoryBuffer>>(Module &)>;
|
||||||
|
|
||||||
using NotifyCompiledFunction =
|
using NotifyCompiledFunction =
|
||||||
std::function<void(VModuleKey K, std::unique_ptr<Module>)>;
|
std::function<void(VModuleKey K, ThreadSafeModule TSM)>;
|
||||||
|
|
||||||
IRCompileLayer2(ExecutionSession &ES, ObjectLayer &BaseLayer,
|
IRCompileLayer2(ExecutionSession &ES, ObjectLayer &BaseLayer,
|
||||||
CompileFunction Compile);
|
CompileFunction Compile);
|
||||||
@ -42,7 +42,7 @@ public:
|
|||||||
void setNotifyCompiled(NotifyCompiledFunction NotifyCompiled);
|
void setNotifyCompiled(NotifyCompiledFunction NotifyCompiled);
|
||||||
|
|
||||||
void emit(MaterializationResponsibility R, VModuleKey K,
|
void emit(MaterializationResponsibility R, VModuleKey K,
|
||||||
std::unique_ptr<Module> M) override;
|
ThreadSafeModule TSM) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
mutable std::mutex IRLayerMutex;
|
mutable std::mutex IRLayerMutex;
|
||||||
|
@ -25,9 +25,8 @@ namespace orc {
|
|||||||
|
|
||||||
class IRTransformLayer2 : public IRLayer {
|
class IRTransformLayer2 : public IRLayer {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
using TransformFunction =
|
using TransformFunction =
|
||||||
std::function<Expected<std::unique_ptr<Module>>(std::unique_ptr<Module>)>;
|
std::function<Expected<ThreadSafeModule>(ThreadSafeModule)>;
|
||||||
|
|
||||||
IRTransformLayer2(ExecutionSession &ES, IRLayer &BaseLayer,
|
IRTransformLayer2(ExecutionSession &ES, IRLayer &BaseLayer,
|
||||||
TransformFunction Transform = identityTransform);
|
TransformFunction Transform = identityTransform);
|
||||||
@ -37,10 +36,10 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void emit(MaterializationResponsibility R, VModuleKey K,
|
void emit(MaterializationResponsibility R, VModuleKey K,
|
||||||
std::unique_ptr<Module> M) override;
|
ThreadSafeModule TSM) override;
|
||||||
|
|
||||||
static std::unique_ptr<Module> identityTransform(std::unique_ptr<Module> M) {
|
static ThreadSafeModule identityTransform(ThreadSafeModule TSM) {
|
||||||
return M;
|
return TSM;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
#include "llvm/ExecutionEngine/Orc/IRTransformLayer.h"
|
#include "llvm/ExecutionEngine/Orc/IRTransformLayer.h"
|
||||||
#include "llvm/ExecutionEngine/Orc/ObjectTransformLayer.h"
|
#include "llvm/ExecutionEngine/Orc/ObjectTransformLayer.h"
|
||||||
#include "llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h"
|
#include "llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h"
|
||||||
|
#include "llvm/ExecutionEngine/Orc/ThreadSafeModule.h"
|
||||||
#include "llvm/Target/TargetMachine.h"
|
#include "llvm/Target/TargetMachine.h"
|
||||||
|
|
||||||
namespace llvm {
|
namespace llvm {
|
||||||
@ -43,11 +44,11 @@ public:
|
|||||||
Error defineAbsolute(StringRef Name, JITEvaluatedSymbol Address);
|
Error defineAbsolute(StringRef Name, JITEvaluatedSymbol Address);
|
||||||
|
|
||||||
/// Adds an IR module to the given JITDylib.
|
/// Adds an IR module to the given JITDylib.
|
||||||
Error addIRModule(JITDylib &JD, std::unique_ptr<Module> M);
|
Error addIRModule(JITDylib &JD, ThreadSafeModule TSM);
|
||||||
|
|
||||||
/// Adds an IR module to the Main JITDylib.
|
/// Adds an IR module to the Main JITDylib.
|
||||||
Error addIRModule(std::unique_ptr<Module> M) {
|
Error addIRModule(ThreadSafeModule TSM) {
|
||||||
return addIRModule(Main, std::move(M));
|
return addIRModule(Main, std::move(TSM));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Adds an object file to the given JITDylib.
|
/// Adds an object file to the given JITDylib.
|
||||||
@ -119,7 +120,7 @@ class LLLazyJIT : public LLJIT {
|
|||||||
public:
|
public:
|
||||||
/// Create an LLLazyJIT instance.
|
/// Create an LLLazyJIT instance.
|
||||||
static Expected<std::unique_ptr<LLLazyJIT>>
|
static Expected<std::unique_ptr<LLLazyJIT>>
|
||||||
Create(std::unique_ptr<TargetMachine> TM, DataLayout DL, LLVMContext &Ctx);
|
Create(std::unique_ptr<TargetMachine> TM, DataLayout DL);
|
||||||
|
|
||||||
/// Set an IR transform (e.g. pass manager pipeline) to run on each function
|
/// Set an IR transform (e.g. pass manager pipeline) to run on each function
|
||||||
/// when it is compiled.
|
/// when it is compiled.
|
||||||
@ -128,16 +129,16 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Add a module to be lazily compiled to JITDylib JD.
|
/// Add a module to be lazily compiled to JITDylib JD.
|
||||||
Error addLazyIRModule(JITDylib &JD, std::unique_ptr<Module> M);
|
Error addLazyIRModule(JITDylib &JD, ThreadSafeModule M);
|
||||||
|
|
||||||
/// Add a module to be lazily compiled to the main JITDylib.
|
/// Add a module to be lazily compiled to the main JITDylib.
|
||||||
Error addLazyIRModule(std::unique_ptr<Module> M) {
|
Error addLazyIRModule(ThreadSafeModule M) {
|
||||||
return addLazyIRModule(Main, std::move(M));
|
return addLazyIRModule(Main, std::move(M));
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
LLLazyJIT(std::unique_ptr<ExecutionSession> ES,
|
LLLazyJIT(std::unique_ptr<ExecutionSession> ES,
|
||||||
std::unique_ptr<TargetMachine> TM, DataLayout DL, LLVMContext &Ctx,
|
std::unique_ptr<TargetMachine> TM, DataLayout DL,
|
||||||
std::unique_ptr<JITCompileCallbackManager> CCMgr,
|
std::unique_ptr<JITCompileCallbackManager> CCMgr,
|
||||||
std::function<std::unique_ptr<IndirectStubsManager>()> ISMBuilder);
|
std::function<std::unique_ptr<IndirectStubsManager>()> ISMBuilder);
|
||||||
|
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
#define LLVM_EXECUTIONENGINE_ORC_LAYER_H
|
#define LLVM_EXECUTIONENGINE_ORC_LAYER_H
|
||||||
|
|
||||||
#include "llvm/ExecutionEngine/Orc/Core.h"
|
#include "llvm/ExecutionEngine/Orc/Core.h"
|
||||||
|
#include "llvm/ExecutionEngine/Orc/ThreadSafeModule.h"
|
||||||
#include "llvm/IR/Module.h"
|
#include "llvm/IR/Module.h"
|
||||||
#include "llvm/Support/MemoryBuffer.h"
|
#include "llvm/Support/MemoryBuffer.h"
|
||||||
|
|
||||||
@ -30,21 +31,36 @@ public:
|
|||||||
/// Returns the ExecutionSession for this layer.
|
/// Returns the ExecutionSession for this layer.
|
||||||
ExecutionSession &getExecutionSession() { return ES; }
|
ExecutionSession &getExecutionSession() { return ES; }
|
||||||
|
|
||||||
|
/// Sets the CloneToNewContextOnEmit flag (false by default).
|
||||||
|
///
|
||||||
|
/// When set, IR modules added to this layer will be cloned on to a new
|
||||||
|
/// context before emit is called. This can be used by clients who want
|
||||||
|
/// to load all IR using one LLVMContext (to save memory via type and
|
||||||
|
/// constant uniquing), but want to move Modules to fresh contexts before
|
||||||
|
/// compiling them to enable concurrent compilation.
|
||||||
|
/// Single threaded clients, or clients who load every module on a new
|
||||||
|
/// context, need not set this.
|
||||||
|
void setCloneToNewContextOnEmit(bool CloneToNewContextOnEmit);
|
||||||
|
|
||||||
|
/// Returns the current value of the CloneToNewContextOnEmit flag.
|
||||||
|
bool getCloneToNewContextOnEmit() const { return CloneToNewContextOnEmit; }
|
||||||
|
|
||||||
/// Adds a MaterializationUnit representing the given IR to the given
|
/// Adds a MaterializationUnit representing the given IR to the given
|
||||||
/// JITDylib.
|
/// JITDylib.
|
||||||
virtual Error add(JITDylib &JD, VModuleKey K, std::unique_ptr<Module> M);
|
virtual Error add(JITDylib &JD, VModuleKey K, ThreadSafeModule TSM);
|
||||||
|
|
||||||
/// Adds a MaterializationUnit representing the given IR to the main
|
/// Adds a MaterializationUnit representing the given IR to the main
|
||||||
/// JITDylib.
|
/// JITDylib.
|
||||||
Error add(VModuleKey K, std::unique_ptr<Module> M) {
|
Error add(VModuleKey K, ThreadSafeModule TSM) {
|
||||||
return add(ES.getMainJITDylib(), K, std::move(M));
|
return add(ES.getMainJITDylib(), K, std::move(TSM));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Emit should materialize the given IR.
|
/// Emit should materialize the given IR.
|
||||||
virtual void emit(MaterializationResponsibility R, VModuleKey K,
|
virtual void emit(MaterializationResponsibility R, VModuleKey K,
|
||||||
std::unique_ptr<Module> M) = 0;
|
ThreadSafeModule TSM) = 0;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
bool CloneToNewContextOnEmit = false;
|
||||||
ExecutionSession &ES;
|
ExecutionSession &ES;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -58,18 +74,18 @@ public:
|
|||||||
|
|
||||||
/// Create an IRMaterializationLayer. Scans the module to build the
|
/// Create an IRMaterializationLayer. Scans the module to build the
|
||||||
/// SymbolFlags and SymbolToDefinition maps.
|
/// SymbolFlags and SymbolToDefinition maps.
|
||||||
IRMaterializationUnit(ExecutionSession &ES, std::unique_ptr<Module> M);
|
IRMaterializationUnit(ExecutionSession &ES, ThreadSafeModule TSM);
|
||||||
|
|
||||||
/// Create an IRMaterializationLayer from a module, and pre-existing
|
/// Create an IRMaterializationLayer from a module, and pre-existing
|
||||||
/// SymbolFlags and SymbolToDefinition maps. The maps must provide
|
/// SymbolFlags and SymbolToDefinition maps. The maps must provide
|
||||||
/// entries for each definition in M.
|
/// entries for each definition in M.
|
||||||
/// This constructor is useful for delegating work from one
|
/// This constructor is useful for delegating work from one
|
||||||
/// IRMaterializationUnit to another.
|
/// IRMaterializationUnit to another.
|
||||||
IRMaterializationUnit(std::unique_ptr<Module> M, SymbolFlagsMap SymbolFlags,
|
IRMaterializationUnit(ThreadSafeModule TSM, SymbolFlagsMap SymbolFlags,
|
||||||
SymbolNameToDefinitionMap SymbolToDefinition);
|
SymbolNameToDefinitionMap SymbolToDefinition);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::unique_ptr<Module> M;
|
ThreadSafeModule TSM;
|
||||||
SymbolNameToDefinitionMap SymbolToDefinition;
|
SymbolNameToDefinitionMap SymbolToDefinition;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -81,7 +97,8 @@ private:
|
|||||||
class BasicIRLayerMaterializationUnit : public IRMaterializationUnit {
|
class BasicIRLayerMaterializationUnit : public IRMaterializationUnit {
|
||||||
public:
|
public:
|
||||||
BasicIRLayerMaterializationUnit(IRLayer &L, VModuleKey K,
|
BasicIRLayerMaterializationUnit(IRLayer &L, VModuleKey K,
|
||||||
std::unique_ptr<Module> M);
|
ThreadSafeModule TSM);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void materialize(MaterializationResponsibility R) override;
|
void materialize(MaterializationResponsibility R) override;
|
||||||
|
124
include/llvm/ExecutionEngine/Orc/ThreadSafeModule.h
Normal file
124
include/llvm/ExecutionEngine/Orc/ThreadSafeModule.h
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
//===----------- ThreadSafeModule.h -- Layer interfaces ---------*- C++ -*-===//
|
||||||
|
//
|
||||||
|
// The LLVM Compiler Infrastructure
|
||||||
|
//
|
||||||
|
// This file is distributed under the University of Illinois Open Source
|
||||||
|
// License. See LICENSE.TXT for details.
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
//
|
||||||
|
// Thread safe wrappers and utilities for Module and LLVMContext.
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#ifndef LLVM_EXECUTIONENGINE_ORC_THREADSAFEMODULEWRAPPER_H
|
||||||
|
#define LLVM_EXECUTIONENGINE_ORC_THREADSAFEMODULEWRAPPER_H
|
||||||
|
|
||||||
|
#include "llvm/IR/LLVMContext.h"
|
||||||
|
#include "llvm/IR/Module.h"
|
||||||
|
|
||||||
|
namespace llvm {
|
||||||
|
namespace orc {
|
||||||
|
|
||||||
|
/// An LLVMContext together with an associated mutex that can be used to lock
|
||||||
|
/// the context to prevent concurrent access by other threads.
|
||||||
|
class ThreadSafeContext {
|
||||||
|
private:
|
||||||
|
|
||||||
|
struct State {
|
||||||
|
State(std::unique_ptr<LLVMContext> Ctx)
|
||||||
|
: Ctx(std::move(Ctx)) {}
|
||||||
|
|
||||||
|
std::unique_ptr<LLVMContext> Ctx;
|
||||||
|
std::recursive_mutex Mutex;
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
// RAII based lock for ThreadSafeContext.
|
||||||
|
class Lock {
|
||||||
|
private:
|
||||||
|
using UnderlyingLock = std::lock_guard<std::recursive_mutex>;
|
||||||
|
public:
|
||||||
|
|
||||||
|
Lock(std::shared_ptr<State> S)
|
||||||
|
: S(std::move(S)),
|
||||||
|
L(llvm::make_unique<UnderlyingLock>(this->S->Mutex)) {}
|
||||||
|
private:
|
||||||
|
std::shared_ptr<State> S;
|
||||||
|
std::unique_ptr<UnderlyingLock> L;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Construct a null context.
|
||||||
|
ThreadSafeContext() = default;
|
||||||
|
|
||||||
|
/// Construct a ThreadSafeContext from the given LLVMContext.
|
||||||
|
ThreadSafeContext(std::unique_ptr<LLVMContext> NewCtx)
|
||||||
|
: S(std::make_shared<State>(std::move(NewCtx))) {
|
||||||
|
assert(S->Ctx != nullptr &&
|
||||||
|
"Can not construct a ThreadSafeContext from a nullptr");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a pointer to the LLVMContext that was used to construct this
|
||||||
|
/// instance, or null if the instance was default constructed.
|
||||||
|
LLVMContext* getContext() {
|
||||||
|
return S ? S->Ctx.get() : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
Lock getLock() {
|
||||||
|
assert(S && "Can not lock an empty ThreadSafeContext");
|
||||||
|
return Lock(S);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::shared_ptr<State> S;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// An LLVM Module together with a shared ThreadSafeContext.
|
||||||
|
class ThreadSafeModule {
|
||||||
|
public:
|
||||||
|
/// Default construct a ThreadSafeModule. This results in a null module and
|
||||||
|
/// null context.
|
||||||
|
ThreadSafeModule() = default;
|
||||||
|
|
||||||
|
/// Construct a ThreadSafeModule from a unique_ptr<Module> and a
|
||||||
|
/// unique_ptr<LLVMContext>. This creates a new ThreadSafeContext from the
|
||||||
|
/// given context.
|
||||||
|
ThreadSafeModule(std::unique_ptr<Module> M,
|
||||||
|
std::unique_ptr<LLVMContext> Ctx)
|
||||||
|
: M(std::move(M)), TSCtx(std::move(Ctx)) {}
|
||||||
|
|
||||||
|
ThreadSafeModule(std::unique_ptr<Module> M,
|
||||||
|
ThreadSafeContext TSCtx)
|
||||||
|
: M(std::move(M)), TSCtx(std::move(TSCtx)) {}
|
||||||
|
|
||||||
|
Module* getModule() { return M.get(); }
|
||||||
|
|
||||||
|
ThreadSafeContext::Lock getContextLock() { return TSCtx.getLock(); }
|
||||||
|
|
||||||
|
explicit operator bool() {
|
||||||
|
if (M) {
|
||||||
|
assert(TSCtx.getContext() && "Non-null module must have non-null context");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::unique_ptr<Module> M;
|
||||||
|
ThreadSafeContext TSCtx;
|
||||||
|
};
|
||||||
|
|
||||||
|
using GVPredicate = std::function<bool(const GlobalValue&)>;
|
||||||
|
using GVModifier = std::function<void(GlobalValue&)>;
|
||||||
|
|
||||||
|
/// Clones the given module on to a new context.
|
||||||
|
ThreadSafeModule
|
||||||
|
cloneToNewContext(ThreadSafeModule &TSMW,
|
||||||
|
GVPredicate ShouldCloneDef = GVPredicate(),
|
||||||
|
GVModifier UpdateClonedDefSource = GVModifier());
|
||||||
|
|
||||||
|
} // End namespace orc
|
||||||
|
} // End namespace llvm
|
||||||
|
|
||||||
|
#endif // LLVM_EXECUTIONENGINE_ORC_THREADSAFEMODULEWRAPPER_H
|
@ -16,6 +16,7 @@ add_llvm_library(LLVMOrcJIT
|
|||||||
OrcMCJITReplacement.cpp
|
OrcMCJITReplacement.cpp
|
||||||
RPCUtils.cpp
|
RPCUtils.cpp
|
||||||
RTDyldObjectLinkingLayer.cpp
|
RTDyldObjectLinkingLayer.cpp
|
||||||
|
ThreadSafeModule.cpp
|
||||||
|
|
||||||
ADDITIONAL_HEADER_DIRS
|
ADDITIONAL_HEADER_DIRS
|
||||||
${LLVM_MAIN_INCLUDE_DIR}/llvm/ExecutionEngine/Orc
|
${LLVM_MAIN_INCLUDE_DIR}/llvm/ExecutionEngine/Orc
|
||||||
|
@ -8,12 +8,8 @@
|
|||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
#include "llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h"
|
#include "llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h"
|
||||||
#include "llvm/Bitcode/BitcodeReader.h"
|
|
||||||
#include "llvm/Bitcode/BitcodeWriter.h"
|
|
||||||
#include "llvm/IR/Mangler.h"
|
#include "llvm/IR/Mangler.h"
|
||||||
#include "llvm/IR/Module.h"
|
#include "llvm/IR/Module.h"
|
||||||
#include "llvm/Support/raw_ostream.h"
|
|
||||||
#include "llvm/Transforms/Utils/Cloning.h"
|
|
||||||
|
|
||||||
using namespace llvm;
|
using namespace llvm;
|
||||||
using namespace llvm::orc;
|
using namespace llvm::orc;
|
||||||
@ -71,56 +67,33 @@ static void extractAliases(MaterializationResponsibility &R, Module &M,
|
|||||||
R.replace(symbolAliases(std::move(Aliases)));
|
R.replace(symbolAliases(std::move(Aliases)));
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::unique_ptr<Module>
|
static ThreadSafeModule extractAndClone(ThreadSafeModule &TSM, StringRef Suffix,
|
||||||
extractAndClone(Module &M, LLVMContext &NewContext, StringRef Suffix,
|
GVPredicate ShouldCloneDefinition) {
|
||||||
function_ref<bool(const GlobalValue *)> ShouldCloneDefinition) {
|
|
||||||
SmallVector<char, 1> ClonedModuleBuffer;
|
|
||||||
|
|
||||||
{
|
auto DeleteClonedDefsAndPromoteDeclLinkages = [](GlobalValue &GV) {
|
||||||
std::set<GlobalValue *> ClonedDefsInSrc;
|
// Delete the definition and bump the linkage in the source module.
|
||||||
ValueToValueMapTy VMap;
|
if (isa<Function>(GV)) {
|
||||||
auto Tmp = CloneModule(M, VMap, [&](const GlobalValue *GV) {
|
auto &F = cast<Function>(GV);
|
||||||
if (ShouldCloneDefinition(GV)) {
|
F.deleteBody();
|
||||||
ClonedDefsInSrc.insert(const_cast<GlobalValue *>(GV));
|
F.setPersonalityFn(nullptr);
|
||||||
return true;
|
} else if (isa<GlobalVariable>(GV)) {
|
||||||
}
|
cast<GlobalVariable>(GV).setInitializer(nullptr);
|
||||||
return false;
|
} else
|
||||||
});
|
llvm_unreachable("Unsupported global type");
|
||||||
|
|
||||||
for (auto *GV : ClonedDefsInSrc) {
|
GV.setLinkage(GlobalValue::ExternalLinkage);
|
||||||
// Delete the definition and bump the linkage in the source module.
|
};
|
||||||
if (isa<Function>(GV)) {
|
|
||||||
auto &F = *cast<Function>(GV);
|
|
||||||
F.deleteBody();
|
|
||||||
F.setPersonalityFn(nullptr);
|
|
||||||
} else if (isa<GlobalVariable>(GV)) {
|
|
||||||
cast<GlobalVariable>(GV)->setInitializer(nullptr);
|
|
||||||
} else
|
|
||||||
llvm_unreachable("Unsupported global type");
|
|
||||||
|
|
||||||
GV->setLinkage(GlobalValue::ExternalLinkage);
|
auto NewTSMod = cloneToNewContext(TSM, ShouldCloneDefinition,
|
||||||
}
|
DeleteClonedDefsAndPromoteDeclLinkages);
|
||||||
|
auto &M = *NewTSMod.getModule();
|
||||||
|
M.setModuleIdentifier((M.getModuleIdentifier() + Suffix).str());
|
||||||
|
|
||||||
BitcodeWriter BCWriter(ClonedModuleBuffer);
|
return NewTSMod;
|
||||||
|
|
||||||
BCWriter.writeModule(*Tmp);
|
|
||||||
BCWriter.writeSymtab();
|
|
||||||
BCWriter.writeStrtab();
|
|
||||||
}
|
|
||||||
|
|
||||||
MemoryBufferRef ClonedModuleBufferRef(
|
|
||||||
StringRef(ClonedModuleBuffer.data(), ClonedModuleBuffer.size()),
|
|
||||||
"cloned module buffer");
|
|
||||||
|
|
||||||
auto ClonedModule =
|
|
||||||
cantFail(parseBitcodeFile(ClonedModuleBufferRef, NewContext));
|
|
||||||
ClonedModule->setModuleIdentifier((M.getName() + Suffix).str());
|
|
||||||
return ClonedModule;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::unique_ptr<Module> extractGlobals(Module &M,
|
static ThreadSafeModule extractGlobals(ThreadSafeModule &TSM) {
|
||||||
LLVMContext &NewContext) {
|
return extractAndClone(TSM, ".globals", [](const GlobalValue &GV) {
|
||||||
return extractAndClone(M, NewContext, ".globals", [](const GlobalValue *GV) {
|
|
||||||
return isa<GlobalVariable>(GV);
|
return isa<GlobalVariable>(GV);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -132,14 +105,14 @@ class ExtractingIRMaterializationUnit : public IRMaterializationUnit {
|
|||||||
public:
|
public:
|
||||||
ExtractingIRMaterializationUnit(ExecutionSession &ES,
|
ExtractingIRMaterializationUnit(ExecutionSession &ES,
|
||||||
CompileOnDemandLayer2 &Parent,
|
CompileOnDemandLayer2 &Parent,
|
||||||
std::unique_ptr<Module> M)
|
ThreadSafeModule TSM)
|
||||||
: IRMaterializationUnit(ES, std::move(M)), Parent(Parent) {}
|
: IRMaterializationUnit(ES, std::move(TSM)), Parent(Parent) {}
|
||||||
|
|
||||||
ExtractingIRMaterializationUnit(std::unique_ptr<Module> M,
|
ExtractingIRMaterializationUnit(ThreadSafeModule TSM,
|
||||||
SymbolFlagsMap SymbolFlags,
|
SymbolFlagsMap SymbolFlags,
|
||||||
SymbolNameToDefinitionMap SymbolToDefinition,
|
SymbolNameToDefinitionMap SymbolToDefinition,
|
||||||
CompileOnDemandLayer2 &Parent)
|
CompileOnDemandLayer2 &Parent)
|
||||||
: IRMaterializationUnit(std::move(M), std::move(SymbolFlags),
|
: IRMaterializationUnit(std::move(TSM), std::move(SymbolFlags),
|
||||||
std::move(SymbolToDefinition)),
|
std::move(SymbolToDefinition)),
|
||||||
Parent(Parent) {}
|
Parent(Parent) {}
|
||||||
|
|
||||||
@ -153,7 +126,7 @@ private:
|
|||||||
auto RequestedSymbols = R.getRequestedSymbols();
|
auto RequestedSymbols = R.getRequestedSymbols();
|
||||||
|
|
||||||
// Extract the requested functions into a new module.
|
// Extract the requested functions into a new module.
|
||||||
std::unique_ptr<Module> ExtractedFunctionsModule;
|
ThreadSafeModule ExtractedFunctionsModule;
|
||||||
if (!RequestedSymbols.empty()) {
|
if (!RequestedSymbols.empty()) {
|
||||||
std::string Suffix;
|
std::string Suffix;
|
||||||
std::set<const GlobalValue *> FunctionsToClone;
|
std::set<const GlobalValue *> FunctionsToClone;
|
||||||
@ -168,10 +141,9 @@ private:
|
|||||||
|
|
||||||
std::lock_guard<std::mutex> Lock(SourceModuleMutex);
|
std::lock_guard<std::mutex> Lock(SourceModuleMutex);
|
||||||
ExtractedFunctionsModule =
|
ExtractedFunctionsModule =
|
||||||
extractAndClone(*M, Parent.GetAvailableContext(), Suffix,
|
extractAndClone(TSM, Suffix, [&](const GlobalValue &GV) -> bool {
|
||||||
[&](const GlobalValue *GV) -> bool {
|
return FunctionsToClone.count(&GV);
|
||||||
return FunctionsToClone.count(GV);
|
});
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build a new ExtractingIRMaterializationUnit to delegate the unrequested
|
// Build a new ExtractingIRMaterializationUnit to delegate the unrequested
|
||||||
@ -193,7 +165,7 @@ private:
|
|||||||
"SymbolFlags and SymbolToDefinition should have the same number "
|
"SymbolFlags and SymbolToDefinition should have the same number "
|
||||||
"of entries");
|
"of entries");
|
||||||
R.replace(llvm::make_unique<ExtractingIRMaterializationUnit>(
|
R.replace(llvm::make_unique<ExtractingIRMaterializationUnit>(
|
||||||
std::move(M), std::move(DelegatedSymbolFlags),
|
std::move(TSM), std::move(DelegatedSymbolFlags),
|
||||||
std::move(DelegatedSymbolToDefinition), Parent));
|
std::move(DelegatedSymbolToDefinition), Parent));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -215,31 +187,30 @@ private:
|
|||||||
|
|
||||||
CompileOnDemandLayer2::CompileOnDemandLayer2(
|
CompileOnDemandLayer2::CompileOnDemandLayer2(
|
||||||
ExecutionSession &ES, IRLayer &BaseLayer, JITCompileCallbackManager &CCMgr,
|
ExecutionSession &ES, IRLayer &BaseLayer, JITCompileCallbackManager &CCMgr,
|
||||||
IndirectStubsManagerBuilder BuildIndirectStubsManager,
|
IndirectStubsManagerBuilder BuildIndirectStubsManager)
|
||||||
GetAvailableContextFunction GetAvailableContext)
|
|
||||||
: IRLayer(ES), BaseLayer(BaseLayer), CCMgr(CCMgr),
|
: IRLayer(ES), BaseLayer(BaseLayer), CCMgr(CCMgr),
|
||||||
BuildIndirectStubsManager(std::move(BuildIndirectStubsManager)),
|
BuildIndirectStubsManager(std::move(BuildIndirectStubsManager)) {}
|
||||||
GetAvailableContext(std::move(GetAvailableContext)) {}
|
|
||||||
|
|
||||||
Error CompileOnDemandLayer2::add(JITDylib &V, VModuleKey K,
|
Error CompileOnDemandLayer2::add(JITDylib &V, VModuleKey K,
|
||||||
std::unique_ptr<Module> M) {
|
ThreadSafeModule TSM) {
|
||||||
return IRLayer::add(V, K, std::move(M));
|
return IRLayer::add(V, K, std::move(TSM));
|
||||||
}
|
}
|
||||||
|
|
||||||
void CompileOnDemandLayer2::emit(MaterializationResponsibility R, VModuleKey K,
|
void CompileOnDemandLayer2::emit(MaterializationResponsibility R, VModuleKey K,
|
||||||
std::unique_ptr<Module> M) {
|
ThreadSafeModule TSM) {
|
||||||
auto &ES = getExecutionSession();
|
auto &ES = getExecutionSession();
|
||||||
assert(M && "M should not be null");
|
assert(TSM && "M should not be null");
|
||||||
|
auto &M = *TSM.getModule();
|
||||||
|
|
||||||
for (auto &GV : M->global_values())
|
for (auto &GV : M.global_values())
|
||||||
if (GV.hasWeakLinkage())
|
if (GV.hasWeakLinkage())
|
||||||
GV.setLinkage(GlobalValue::ExternalLinkage);
|
GV.setLinkage(GlobalValue::ExternalLinkage);
|
||||||
|
|
||||||
MangleAndInterner Mangle(ES, M->getDataLayout());
|
MangleAndInterner Mangle(ES, M.getDataLayout());
|
||||||
|
|
||||||
extractAliases(R, *M, Mangle);
|
extractAliases(R, *TSM.getModule(), Mangle);
|
||||||
|
|
||||||
auto GlobalsModule = extractGlobals(*M, GetAvailableContext());
|
auto GlobalsModule = extractGlobals(TSM);
|
||||||
|
|
||||||
// Delete the bodies of any available externally functions, rename the
|
// Delete the bodies of any available externally functions, rename the
|
||||||
// rest, and build the compile callbacks.
|
// rest, and build the compile callbacks.
|
||||||
@ -247,7 +218,7 @@ void CompileOnDemandLayer2::emit(MaterializationResponsibility R, VModuleKey K,
|
|||||||
StubCallbacksAndLinkages;
|
StubCallbacksAndLinkages;
|
||||||
auto &TargetJD = R.getTargetJITDylib();
|
auto &TargetJD = R.getTargetJITDylib();
|
||||||
|
|
||||||
for (auto &F : M->functions()) {
|
for (auto &F : M.functions()) {
|
||||||
if (F.isDeclaration())
|
if (F.isDeclaration())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@ -260,7 +231,7 @@ void CompileOnDemandLayer2::emit(MaterializationResponsibility R, VModuleKey K,
|
|||||||
assert(F.hasName() && "Function should have a name");
|
assert(F.hasName() && "Function should have a name");
|
||||||
std::string StubUnmangledName = F.getName();
|
std::string StubUnmangledName = F.getName();
|
||||||
F.setName(F.getName() + "$body");
|
F.setName(F.getName() + "$body");
|
||||||
auto StubDecl = cloneFunctionDecl(*M, F);
|
auto StubDecl = cloneFunctionDecl(*TSM.getModule(), F);
|
||||||
StubDecl->setName(StubUnmangledName);
|
StubDecl->setName(StubUnmangledName);
|
||||||
StubDecl->setPersonalityFn(nullptr);
|
StubDecl->setPersonalityFn(nullptr);
|
||||||
StubDecl->setLinkage(GlobalValue::ExternalLinkage);
|
StubDecl->setLinkage(GlobalValue::ExternalLinkage);
|
||||||
@ -296,7 +267,7 @@ void CompileOnDemandLayer2::emit(MaterializationResponsibility R, VModuleKey K,
|
|||||||
// Build the function-body-extracting materialization unit.
|
// Build the function-body-extracting materialization unit.
|
||||||
if (auto Err = R.getTargetJITDylib().define(
|
if (auto Err = R.getTargetJITDylib().define(
|
||||||
llvm::make_unique<ExtractingIRMaterializationUnit>(ES, *this,
|
llvm::make_unique<ExtractingIRMaterializationUnit>(ES, *this,
|
||||||
std::move(M)))) {
|
std::move(TSM)))) {
|
||||||
ES.reportError(std::move(Err));
|
ES.reportError(std::move(Err));
|
||||||
R.failMaterialization();
|
R.failMaterialization();
|
||||||
return;
|
return;
|
||||||
@ -335,9 +306,9 @@ CompileOnDemandLayer2::getStubsManager(const JITDylib &V) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void CompileOnDemandLayer2::emitExtractedFunctionsModule(
|
void CompileOnDemandLayer2::emitExtractedFunctionsModule(
|
||||||
MaterializationResponsibility R, std::unique_ptr<Module> M) {
|
MaterializationResponsibility R, ThreadSafeModule TSM) {
|
||||||
auto K = getExecutionSession().allocateVModule();
|
auto K = getExecutionSession().allocateVModule();
|
||||||
BaseLayer.emit(std::move(R), std::move(K), std::move(M));
|
BaseLayer.emit(std::move(R), std::move(K), std::move(TSM));
|
||||||
}
|
}
|
||||||
|
|
||||||
} // end namespace orc
|
} // end namespace orc
|
||||||
|
@ -22,16 +22,16 @@ void IRCompileLayer2::setNotifyCompiled(NotifyCompiledFunction NotifyCompiled) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void IRCompileLayer2::emit(MaterializationResponsibility R, VModuleKey K,
|
void IRCompileLayer2::emit(MaterializationResponsibility R, VModuleKey K,
|
||||||
std::unique_ptr<Module> M) {
|
ThreadSafeModule TSM) {
|
||||||
assert(M && "Module must not be null");
|
assert(TSM.getModule() && "Module must not be null");
|
||||||
|
|
||||||
if (auto Obj = Compile(*M)) {
|
if (auto Obj = Compile(*TSM.getModule())) {
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> Lock(IRLayerMutex);
|
std::lock_guard<std::mutex> Lock(IRLayerMutex);
|
||||||
if (NotifyCompiled)
|
if (NotifyCompiled)
|
||||||
NotifyCompiled(K, std::move(M));
|
NotifyCompiled(K, std::move(TSM));
|
||||||
else
|
else
|
||||||
M = nullptr;
|
TSM = ThreadSafeModule();
|
||||||
}
|
}
|
||||||
BaseLayer.emit(std::move(R), std::move(K), std::move(*Obj));
|
BaseLayer.emit(std::move(R), std::move(K), std::move(*Obj));
|
||||||
} else {
|
} else {
|
||||||
|
@ -19,14 +19,14 @@ IRTransformLayer2::IRTransformLayer2(ExecutionSession &ES,
|
|||||||
: IRLayer(ES), BaseLayer(BaseLayer), Transform(std::move(Transform)) {}
|
: IRLayer(ES), BaseLayer(BaseLayer), Transform(std::move(Transform)) {}
|
||||||
|
|
||||||
void IRTransformLayer2::emit(MaterializationResponsibility R, VModuleKey K,
|
void IRTransformLayer2::emit(MaterializationResponsibility R, VModuleKey K,
|
||||||
std::unique_ptr<Module> M) {
|
ThreadSafeModule TSM) {
|
||||||
assert(M && "Module must not be null");
|
assert(TSM.getModule() && "Module must not be null");
|
||||||
|
|
||||||
if (auto TransformedMod = Transform(std::move(M)))
|
if (auto TransformedTSM = Transform(std::move(TSM)))
|
||||||
BaseLayer.emit(std::move(R), std::move(K), std::move(*TransformedMod));
|
BaseLayer.emit(std::move(R), std::move(K), std::move(*TransformedTSM));
|
||||||
else {
|
else {
|
||||||
R.failMaterialization();
|
R.failMaterialization();
|
||||||
getExecutionSession().reportError(TransformedMod.takeError());
|
getExecutionSession().reportError(TransformedTSM.takeError());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,14 +27,14 @@ Error LLJIT::defineAbsolute(StringRef Name, JITEvaluatedSymbol Sym) {
|
|||||||
return Main.define(absoluteSymbols(std::move(Symbols)));
|
return Main.define(absoluteSymbols(std::move(Symbols)));
|
||||||
}
|
}
|
||||||
|
|
||||||
Error LLJIT::addIRModule(JITDylib &JD, std::unique_ptr<Module> M) {
|
Error LLJIT::addIRModule(JITDylib &JD, ThreadSafeModule TSM) {
|
||||||
assert(M && "Can not add null module");
|
assert(TSM && "Can not add null module");
|
||||||
|
|
||||||
if (auto Err = applyDataLayout(*M))
|
if (auto Err = applyDataLayout(*TSM.getModule()))
|
||||||
return Err;
|
return Err;
|
||||||
|
|
||||||
auto K = ES->allocateVModule();
|
auto K = ES->allocateVModule();
|
||||||
return CompileLayer.add(JD, K, std::move(M));
|
return CompileLayer.add(JD, K, std::move(TSM));
|
||||||
}
|
}
|
||||||
|
|
||||||
Error LLJIT::addObjectFile(JITDylib &JD, std::unique_ptr<MemoryBuffer> Obj) {
|
Error LLJIT::addObjectFile(JITDylib &JD, std::unique_ptr<MemoryBuffer> Obj) {
|
||||||
@ -90,8 +90,7 @@ void LLJIT::recordCtorDtors(Module &M) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Expected<std::unique_ptr<LLLazyJIT>>
|
Expected<std::unique_ptr<LLLazyJIT>>
|
||||||
LLLazyJIT::Create(std::unique_ptr<TargetMachine> TM, DataLayout DL,
|
LLLazyJIT::Create(std::unique_ptr<TargetMachine> TM, DataLayout DL) {
|
||||||
LLVMContext &Ctx) {
|
|
||||||
auto ES = llvm::make_unique<ExecutionSession>();
|
auto ES = llvm::make_unique<ExecutionSession>();
|
||||||
|
|
||||||
const Triple &TT = TM->getTargetTriple();
|
const Triple &TT = TM->getTargetTriple();
|
||||||
@ -109,33 +108,32 @@ LLLazyJIT::Create(std::unique_ptr<TargetMachine> TM, DataLayout DL,
|
|||||||
inconvertibleErrorCode());
|
inconvertibleErrorCode());
|
||||||
|
|
||||||
return std::unique_ptr<LLLazyJIT>(
|
return std::unique_ptr<LLLazyJIT>(
|
||||||
new LLLazyJIT(std::move(ES), std::move(TM), std::move(DL), Ctx,
|
new LLLazyJIT(std::move(ES), std::move(TM), std::move(DL),
|
||||||
std::move(CCMgr), std::move(ISMBuilder)));
|
std::move(CCMgr), std::move(ISMBuilder)));
|
||||||
}
|
}
|
||||||
|
|
||||||
Error LLLazyJIT::addLazyIRModule(JITDylib &JD, std::unique_ptr<Module> M) {
|
Error LLLazyJIT::addLazyIRModule(JITDylib &JD, ThreadSafeModule TSM) {
|
||||||
assert(M && "Can not add null module");
|
assert(TSM && "Can not add null module");
|
||||||
|
|
||||||
if (auto Err = applyDataLayout(*M))
|
if (auto Err = applyDataLayout(*TSM.getModule()))
|
||||||
return Err;
|
return Err;
|
||||||
|
|
||||||
makeAllSymbolsExternallyAccessible(*M);
|
makeAllSymbolsExternallyAccessible(*TSM.getModule());
|
||||||
|
|
||||||
recordCtorDtors(*M);
|
recordCtorDtors(*TSM.getModule());
|
||||||
|
|
||||||
auto K = ES->allocateVModule();
|
auto K = ES->allocateVModule();
|
||||||
return CODLayer.add(JD, K, std::move(M));
|
return CODLayer.add(JD, K, std::move(TSM));
|
||||||
}
|
}
|
||||||
|
|
||||||
LLLazyJIT::LLLazyJIT(
|
LLLazyJIT::LLLazyJIT(
|
||||||
std::unique_ptr<ExecutionSession> ES, std::unique_ptr<TargetMachine> TM,
|
std::unique_ptr<ExecutionSession> ES, std::unique_ptr<TargetMachine> TM,
|
||||||
DataLayout DL, LLVMContext &Ctx,
|
DataLayout DL, std::unique_ptr<JITCompileCallbackManager> CCMgr,
|
||||||
std::unique_ptr<JITCompileCallbackManager> CCMgr,
|
|
||||||
std::function<std::unique_ptr<IndirectStubsManager>()> ISMBuilder)
|
std::function<std::unique_ptr<IndirectStubsManager>()> ISMBuilder)
|
||||||
: LLJIT(std::move(ES), std::move(TM), std::move(DL)),
|
: LLJIT(std::move(ES), std::move(TM), std::move(DL)),
|
||||||
CCMgr(std::move(CCMgr)), TransformLayer(*this->ES, CompileLayer),
|
CCMgr(std::move(CCMgr)), TransformLayer(*this->ES, CompileLayer),
|
||||||
CODLayer(*this->ES, TransformLayer, *this->CCMgr, std::move(ISMBuilder),
|
CODLayer(*this->ES, TransformLayer, *this->CCMgr, std::move(ISMBuilder)) {
|
||||||
[&]() -> LLVMContext & { return Ctx; }) {}
|
}
|
||||||
|
|
||||||
} // End namespace orc.
|
} // End namespace orc.
|
||||||
} // End namespace llvm.
|
} // End namespace llvm.
|
||||||
|
@ -16,17 +16,19 @@ namespace orc {
|
|||||||
IRLayer::IRLayer(ExecutionSession &ES) : ES(ES) {}
|
IRLayer::IRLayer(ExecutionSession &ES) : ES(ES) {}
|
||||||
IRLayer::~IRLayer() {}
|
IRLayer::~IRLayer() {}
|
||||||
|
|
||||||
Error IRLayer::add(JITDylib &JD, VModuleKey K, std::unique_ptr<Module> M) {
|
Error IRLayer::add(JITDylib &JD, VModuleKey K, ThreadSafeModule TSM) {
|
||||||
return JD.define(llvm::make_unique<BasicIRLayerMaterializationUnit>(
|
return JD.define(llvm::make_unique<BasicIRLayerMaterializationUnit>(
|
||||||
*this, std::move(K), std::move(M)));
|
*this, std::move(K), std::move(TSM)));
|
||||||
}
|
}
|
||||||
|
|
||||||
IRMaterializationUnit::IRMaterializationUnit(ExecutionSession &ES,
|
IRMaterializationUnit::IRMaterializationUnit(ExecutionSession &ES,
|
||||||
std::unique_ptr<Module> M)
|
ThreadSafeModule TSM)
|
||||||
: MaterializationUnit(SymbolFlagsMap()), M(std::move(M)) {
|
: MaterializationUnit(SymbolFlagsMap()), TSM(std::move(TSM)) {
|
||||||
|
|
||||||
MangleAndInterner Mangle(ES, this->M->getDataLayout());
|
assert(this->TSM && "Module must not be null");
|
||||||
for (auto &G : this->M->global_values()) {
|
|
||||||
|
MangleAndInterner Mangle(ES, this->TSM.getModule()->getDataLayout());
|
||||||
|
for (auto &G : this->TSM.getModule()->global_values()) {
|
||||||
if (G.hasName() && !G.isDeclaration() && !G.hasLocalLinkage() &&
|
if (G.hasName() && !G.isDeclaration() && !G.hasLocalLinkage() &&
|
||||||
!G.hasAvailableExternallyLinkage() && !G.hasAppendingLinkage()) {
|
!G.hasAvailableExternallyLinkage() && !G.hasAppendingLinkage()) {
|
||||||
auto MangledName = Mangle(G.getName());
|
auto MangledName = Mangle(G.getName());
|
||||||
@ -37,9 +39,9 @@ IRMaterializationUnit::IRMaterializationUnit(ExecutionSession &ES,
|
|||||||
}
|
}
|
||||||
|
|
||||||
IRMaterializationUnit::IRMaterializationUnit(
|
IRMaterializationUnit::IRMaterializationUnit(
|
||||||
std::unique_ptr<Module> M, SymbolFlagsMap SymbolFlags,
|
ThreadSafeModule TSM, SymbolFlagsMap SymbolFlags,
|
||||||
SymbolNameToDefinitionMap SymbolToDefinition)
|
SymbolNameToDefinitionMap SymbolToDefinition)
|
||||||
: MaterializationUnit(std::move(SymbolFlags)), M(std::move(M)),
|
: MaterializationUnit(std::move(SymbolFlags)), TSM(std::move(TSM)),
|
||||||
SymbolToDefinition(std::move(SymbolToDefinition)) {}
|
SymbolToDefinition(std::move(SymbolToDefinition)) {}
|
||||||
|
|
||||||
void IRMaterializationUnit::discard(const JITDylib &JD, SymbolStringPtr Name) {
|
void IRMaterializationUnit::discard(const JITDylib &JD, SymbolStringPtr Name) {
|
||||||
@ -53,13 +55,18 @@ void IRMaterializationUnit::discard(const JITDylib &JD, SymbolStringPtr Name) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
BasicIRLayerMaterializationUnit::BasicIRLayerMaterializationUnit(
|
BasicIRLayerMaterializationUnit::BasicIRLayerMaterializationUnit(
|
||||||
IRLayer &L, VModuleKey K, std::unique_ptr<Module> M)
|
IRLayer &L, VModuleKey K, ThreadSafeModule TSM)
|
||||||
: IRMaterializationUnit(L.getExecutionSession(), std::move(M)),
|
: IRMaterializationUnit(L.getExecutionSession(), std::move(TSM)), L(L),
|
||||||
L(L), K(std::move(K)) {}
|
K(std::move(K)) {}
|
||||||
|
|
||||||
void BasicIRLayerMaterializationUnit::materialize(
|
void BasicIRLayerMaterializationUnit::materialize(
|
||||||
MaterializationResponsibility R) {
|
MaterializationResponsibility R) {
|
||||||
L.emit(std::move(R), std::move(K), std::move(M));
|
|
||||||
|
if (L.getCloneToNewContextOnEmit())
|
||||||
|
TSM = cloneToNewContext(TSM);
|
||||||
|
|
||||||
|
auto Lock = TSM.getContextLock();
|
||||||
|
L.emit(std::move(R), std::move(K), std::move(TSM));
|
||||||
}
|
}
|
||||||
|
|
||||||
ObjectLayer::ObjectLayer(ExecutionSession &ES) : ES(ES) {}
|
ObjectLayer::ObjectLayer(ExecutionSession &ES) : ES(ES) {}
|
||||||
|
65
lib/ExecutionEngine/Orc/ThreadSafeModule.cpp
Normal file
65
lib/ExecutionEngine/Orc/ThreadSafeModule.cpp
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
//===-- ThreadSafeModule.cpp - Thread safe Module, Context, and Utilities h-===//
|
||||||
|
//
|
||||||
|
// The LLVM Compiler Infrastructure
|
||||||
|
//
|
||||||
|
// This file is distributed under the University of Illinois Open Source
|
||||||
|
// License. See LICENSE.TXT for details.
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#include "llvm/ExecutionEngine/Orc/ThreadSafeModule.h"
|
||||||
|
#include "llvm/Bitcode/BitcodeReader.h"
|
||||||
|
#include "llvm/Bitcode/BitcodeWriter.h"
|
||||||
|
#include "llvm/Transforms/Utils/Cloning.h"
|
||||||
|
|
||||||
|
namespace llvm {
|
||||||
|
namespace orc {
|
||||||
|
|
||||||
|
ThreadSafeModule cloneToNewContext(ThreadSafeModule &TSM,
|
||||||
|
GVPredicate ShouldCloneDef,
|
||||||
|
GVModifier UpdateClonedDefSource) {
|
||||||
|
assert(TSM && "Can not clone null module");
|
||||||
|
|
||||||
|
if (!ShouldCloneDef)
|
||||||
|
ShouldCloneDef = [](const GlobalValue&) { return true; };
|
||||||
|
|
||||||
|
auto Lock = TSM.getContextLock();
|
||||||
|
|
||||||
|
SmallVector<char, 1> ClonedModuleBuffer;
|
||||||
|
|
||||||
|
{
|
||||||
|
std::vector<GlobalValue *> ClonedDefsInSrc;
|
||||||
|
ValueToValueMapTy VMap;
|
||||||
|
auto Tmp = CloneModule(*TSM.getModule(), VMap,
|
||||||
|
[&](const GlobalValue *GV) {
|
||||||
|
if (ShouldCloneDef(*GV)) {
|
||||||
|
ClonedDefsInSrc.push_back(const_cast<GlobalValue *>(GV));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (UpdateClonedDefSource)
|
||||||
|
for (auto *GV : ClonedDefsInSrc)
|
||||||
|
UpdateClonedDefSource(*GV);
|
||||||
|
|
||||||
|
BitcodeWriter BCWriter(ClonedModuleBuffer);
|
||||||
|
|
||||||
|
BCWriter.writeModule(*Tmp);
|
||||||
|
BCWriter.writeSymtab();
|
||||||
|
BCWriter.writeStrtab();
|
||||||
|
}
|
||||||
|
|
||||||
|
MemoryBufferRef ClonedModuleBufferRef(
|
||||||
|
StringRef(ClonedModuleBuffer.data(), ClonedModuleBuffer.size()),
|
||||||
|
"cloned module buffer");
|
||||||
|
ThreadSafeContext NewTSCtx(llvm::make_unique<LLVMContext>());
|
||||||
|
|
||||||
|
auto ClonedModule =
|
||||||
|
cantFail(parseBitcodeFile(ClonedModuleBufferRef, *NewTSCtx.getContext()));
|
||||||
|
ClonedModule->setModuleIdentifier(TSM.getModule()->getName());
|
||||||
|
return ThreadSafeModule(std::move(ClonedModule), std::move(NewTSCtx));
|
||||||
|
}
|
||||||
|
|
||||||
|
} // end namespace orc
|
||||||
|
} // end namespace llvm
|
@ -678,13 +678,13 @@ int main(int argc, char **argv, char * const *envp) {
|
|||||||
static orc::IRTransformLayer2::TransformFunction createDebugDumper() {
|
static orc::IRTransformLayer2::TransformFunction createDebugDumper() {
|
||||||
switch (OrcDumpKind) {
|
switch (OrcDumpKind) {
|
||||||
case DumpKind::NoDump:
|
case DumpKind::NoDump:
|
||||||
return [](std::unique_ptr<Module> M) { return M; };
|
return [](orc::ThreadSafeModule TSM) { return TSM; };
|
||||||
|
|
||||||
case DumpKind::DumpFuncsToStdOut:
|
case DumpKind::DumpFuncsToStdOut:
|
||||||
return [](std::unique_ptr<Module> M) {
|
return [](orc::ThreadSafeModule TSM) {
|
||||||
printf("[ ");
|
printf("[ ");
|
||||||
|
|
||||||
for (const auto &F : *M) {
|
for (const auto &F : *TSM.getModule()) {
|
||||||
if (F.isDeclaration())
|
if (F.isDeclaration())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@ -696,28 +696,29 @@ static orc::IRTransformLayer2::TransformFunction createDebugDumper() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
printf("]\n");
|
printf("]\n");
|
||||||
return M;
|
return TSM;
|
||||||
};
|
};
|
||||||
|
|
||||||
case DumpKind::DumpModsToStdOut:
|
case DumpKind::DumpModsToStdOut:
|
||||||
return [](std::unique_ptr<Module> M) {
|
return [](orc::ThreadSafeModule TSM) {
|
||||||
outs() << "----- Module Start -----\n"
|
outs() << "----- Module Start -----\n"
|
||||||
<< *M << "----- Module End -----\n";
|
<< *TSM.getModule() << "----- Module End -----\n";
|
||||||
|
|
||||||
return M;
|
return TSM;
|
||||||
};
|
};
|
||||||
|
|
||||||
case DumpKind::DumpModsToDisk:
|
case DumpKind::DumpModsToDisk:
|
||||||
return [](std::unique_ptr<Module> M) {
|
return [](orc::ThreadSafeModule TSM) {
|
||||||
std::error_code EC;
|
std::error_code EC;
|
||||||
raw_fd_ostream Out(M->getModuleIdentifier() + ".ll", EC, sys::fs::F_Text);
|
raw_fd_ostream Out(TSM.getModule()->getModuleIdentifier() + ".ll", EC,
|
||||||
|
sys::fs::F_Text);
|
||||||
if (EC) {
|
if (EC) {
|
||||||
errs() << "Couldn't open " << M->getModuleIdentifier()
|
errs() << "Couldn't open " << TSM.getModule()->getModuleIdentifier()
|
||||||
<< " for dumping.\nError:" << EC.message() << "\n";
|
<< " for dumping.\nError:" << EC.message() << "\n";
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
Out << *M;
|
Out << *TSM.getModule();
|
||||||
return M;
|
return TSM;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
llvm_unreachable("Unknown DumpKind");
|
llvm_unreachable("Unknown DumpKind");
|
||||||
@ -736,13 +737,14 @@ int runOrcLazyJIT(const char *ProgName) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Parse the main module.
|
// Parse the main module.
|
||||||
LLVMContext Ctx;
|
orc::ThreadSafeContext TSCtx(llvm::make_unique<LLVMContext>());
|
||||||
SMDiagnostic Err;
|
SMDiagnostic Err;
|
||||||
auto MainModule = parseIRFile(InputFile, Err, Ctx);
|
auto MainModule = orc::ThreadSafeModule(
|
||||||
|
parseIRFile(InputFile, Err, *TSCtx.getContext()), TSCtx);
|
||||||
if (!MainModule)
|
if (!MainModule)
|
||||||
reportError(Err, ProgName);
|
reportError(Err, ProgName);
|
||||||
|
|
||||||
const auto &TT = MainModule->getTargetTriple();
|
const auto &TT = MainModule.getModule()->getTargetTriple();
|
||||||
orc::JITTargetMachineBuilder TMD =
|
orc::JITTargetMachineBuilder TMD =
|
||||||
TT.empty() ? ExitOnErr(orc::JITTargetMachineBuilder::detectHost())
|
TT.empty() ? ExitOnErr(orc::JITTargetMachineBuilder::detectHost())
|
||||||
: orc::JITTargetMachineBuilder(Triple(TT));
|
: orc::JITTargetMachineBuilder(Triple(TT));
|
||||||
@ -758,18 +760,17 @@ int runOrcLazyJIT(const char *ProgName) {
|
|||||||
: None);
|
: None);
|
||||||
auto TM = ExitOnErr(TMD.createTargetMachine());
|
auto TM = ExitOnErr(TMD.createTargetMachine());
|
||||||
auto DL = TM->createDataLayout();
|
auto DL = TM->createDataLayout();
|
||||||
auto J = ExitOnErr(orc::LLLazyJIT::Create(std::move(TM), DL, Ctx));
|
auto J = ExitOnErr(orc::LLLazyJIT::Create(std::move(TM), DL));
|
||||||
|
|
||||||
auto Dump = createDebugDumper();
|
auto Dump = createDebugDumper();
|
||||||
|
|
||||||
J->setLazyCompileTransform(
|
J->setLazyCompileTransform([&](orc::ThreadSafeModule TSM) {
|
||||||
[&](std::unique_ptr<Module> M) {
|
if (verifyModule(*TSM.getModule(), &dbgs())) {
|
||||||
if (verifyModule(*M, &dbgs())) {
|
dbgs() << "Bad module: " << *TSM.getModule() << "\n";
|
||||||
dbgs() << "Bad module: " << *M << "\n";
|
exit(1);
|
||||||
exit(1);
|
}
|
||||||
}
|
return Dump(std::move(TSM));
|
||||||
return Dump(std::move(M));
|
});
|
||||||
});
|
|
||||||
J->getMainJITDylib().setFallbackDefinitionGenerator(
|
J->getMainJITDylib().setFallbackDefinitionGenerator(
|
||||||
orc::DynamicLibraryFallbackGenerator(
|
orc::DynamicLibraryFallbackGenerator(
|
||||||
std::move(LibLLI), DL, [](orc::SymbolStringPtr) { return true; }));
|
std::move(LibLLI), DL, [](orc::SymbolStringPtr) { return true; }));
|
||||||
@ -783,12 +784,12 @@ int runOrcLazyJIT(const char *ProgName) {
|
|||||||
|
|
||||||
// Add any extra modules.
|
// Add any extra modules.
|
||||||
for (auto &ModulePath : ExtraModules) {
|
for (auto &ModulePath : ExtraModules) {
|
||||||
auto M = parseIRFile(ModulePath, Err, Ctx);
|
auto M = parseIRFile(ModulePath, Err, *TSCtx.getContext());
|
||||||
if (!M)
|
if (!M)
|
||||||
reportError(Err, ProgName);
|
reportError(Err, ProgName);
|
||||||
|
|
||||||
orc::makeAllSymbolsExternallyAccessible(*M);
|
orc::makeAllSymbolsExternallyAccessible(*M);
|
||||||
ExitOnErr(J->addLazyIRModule(std::move(M)));
|
ExitOnErr(J->addLazyIRModule(orc::ThreadSafeModule(std::move(M), TSCtx)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add the objects.
|
// Add the objects.
|
||||||
|
@ -126,23 +126,25 @@ TEST(RTDyldObjectLinkingLayer2Test, TestOverrideObjectFlags) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Create a module with two void() functions: foo and bar.
|
// Create a module with two void() functions: foo and bar.
|
||||||
LLVMContext Context;
|
ThreadSafeContext TSCtx(llvm::make_unique<LLVMContext>());
|
||||||
std::unique_ptr<Module> M;
|
ThreadSafeModule M;
|
||||||
{
|
{
|
||||||
ModuleBuilder MB(Context, TM->getTargetTriple().str(), "dummy");
|
ModuleBuilder MB(*TSCtx.getContext(), TM->getTargetTriple().str(), "dummy");
|
||||||
MB.getModule()->setDataLayout(TM->createDataLayout());
|
MB.getModule()->setDataLayout(TM->createDataLayout());
|
||||||
|
|
||||||
Function *FooImpl = MB.createFunctionDecl<void()>("foo");
|
Function *FooImpl = MB.createFunctionDecl<void()>("foo");
|
||||||
BasicBlock *FooEntry = BasicBlock::Create(Context, "entry", FooImpl);
|
BasicBlock *FooEntry =
|
||||||
|
BasicBlock::Create(*TSCtx.getContext(), "entry", FooImpl);
|
||||||
IRBuilder<> B1(FooEntry);
|
IRBuilder<> B1(FooEntry);
|
||||||
B1.CreateRetVoid();
|
B1.CreateRetVoid();
|
||||||
|
|
||||||
Function *BarImpl = MB.createFunctionDecl<void()>("bar");
|
Function *BarImpl = MB.createFunctionDecl<void()>("bar");
|
||||||
BasicBlock *BarEntry = BasicBlock::Create(Context, "entry", BarImpl);
|
BasicBlock *BarEntry =
|
||||||
|
BasicBlock::Create(*TSCtx.getContext(), "entry", BarImpl);
|
||||||
IRBuilder<> B2(BarEntry);
|
IRBuilder<> B2(BarEntry);
|
||||||
B2.CreateRetVoid();
|
B2.CreateRetVoid();
|
||||||
|
|
||||||
M = MB.takeModule();
|
M = ThreadSafeModule(MB.takeModule(), std::move(TSCtx));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a simple stack and set the override flags option.
|
// Create a simple stack and set the override flags option.
|
||||||
@ -192,18 +194,19 @@ TEST(RTDyldObjectLinkingLayer2Test, TestAutoClaimResponsibilityForSymbols) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Create a module with two void() functions: foo and bar.
|
// Create a module with two void() functions: foo and bar.
|
||||||
LLVMContext Context;
|
ThreadSafeContext TSCtx(llvm::make_unique<LLVMContext>());
|
||||||
std::unique_ptr<Module> M;
|
ThreadSafeModule M;
|
||||||
{
|
{
|
||||||
ModuleBuilder MB(Context, TM->getTargetTriple().str(), "dummy");
|
ModuleBuilder MB(*TSCtx.getContext(), TM->getTargetTriple().str(), "dummy");
|
||||||
MB.getModule()->setDataLayout(TM->createDataLayout());
|
MB.getModule()->setDataLayout(TM->createDataLayout());
|
||||||
|
|
||||||
Function *FooImpl = MB.createFunctionDecl<void()>("foo");
|
Function *FooImpl = MB.createFunctionDecl<void()>("foo");
|
||||||
BasicBlock *FooEntry = BasicBlock::Create(Context, "entry", FooImpl);
|
BasicBlock *FooEntry =
|
||||||
|
BasicBlock::Create(*TSCtx.getContext(), "entry", FooImpl);
|
||||||
IRBuilder<> B(FooEntry);
|
IRBuilder<> B(FooEntry);
|
||||||
B.CreateRetVoid();
|
B.CreateRetVoid();
|
||||||
|
|
||||||
M = MB.takeModule();
|
M = ThreadSafeModule(MB.takeModule(), std::move(TSCtx));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a simple stack and set the override flags option.
|
// Create a simple stack and set the override flags option.
|
||||||
|
Loading…
Reference in New Issue
Block a user