mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-22 02:33:06 +01:00
[ORC] Remove OrcV1 APIs.
This removes all legacy layers, legacy utilities, the old Orc C bindings, OrcMCJITReplacement, and OrcMCJITReplacement regression tests. ExecutionEngine and MCJIT are not affected by this change.
This commit is contained in:
parent
159c8567b3
commit
2d8b3a7239
@ -1,169 +0,0 @@
|
||||
/*===----------- llvm-c/OrcBindings.h - Orc Lib C Iface ---------*- C++ -*-===*\
|
||||
|* *|
|
||||
|* Part of the LLVM Project, under the Apache License v2.0 with LLVM *|
|
||||
|* Exceptions. *|
|
||||
|* See https://llvm.org/LICENSE.txt for license information. *|
|
||||
|* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception *|
|
||||
|* *|
|
||||
|*===----------------------------------------------------------------------===*|
|
||||
|* *|
|
||||
|* This header declares the C interface to libLLVMOrcJIT.a, which implements *|
|
||||
|* JIT compilation of LLVM IR. *|
|
||||
|* *|
|
||||
|* Many exotic languages can interoperate with C code but have a harder time *|
|
||||
|* with C++ due to name mangling. So in addition to C, this interface enables *|
|
||||
|* tools written in such languages. *|
|
||||
|* *|
|
||||
|* Note: This interface is experimental. It is *NOT* stable, and may be *|
|
||||
|* changed without warning. *|
|
||||
|* *|
|
||||
\*===----------------------------------------------------------------------===*/
|
||||
|
||||
#ifndef LLVM_C_ORCBINDINGS_H
|
||||
#define LLVM_C_ORCBINDINGS_H
|
||||
|
||||
#include "llvm-c/Error.h"
|
||||
#include "llvm-c/ExternC.h"
|
||||
#include "llvm-c/Object.h"
|
||||
#include "llvm-c/TargetMachine.h"
|
||||
|
||||
LLVM_C_EXTERN_C_BEGIN
|
||||
|
||||
typedef struct LLVMOrcOpaqueJITStack *LLVMOrcJITStackRef;
|
||||
typedef uint64_t LLVMOrcModuleHandle;
|
||||
typedef uint64_t LLVMOrcTargetAddress;
|
||||
typedef uint64_t (*LLVMOrcSymbolResolverFn)(const char *Name, void *LookupCtx);
|
||||
typedef uint64_t (*LLVMOrcLazyCompileCallbackFn)(LLVMOrcJITStackRef JITStack,
|
||||
void *CallbackCtx);
|
||||
|
||||
/**
|
||||
* Create an ORC JIT stack.
|
||||
*
|
||||
* The client owns the resulting stack, and must call OrcDisposeInstance(...)
|
||||
* to destroy it and free its memory. The JIT stack will take ownership of the
|
||||
* TargetMachine, which will be destroyed when the stack is destroyed. The
|
||||
* client should not attempt to dispose of the Target Machine, or it will result
|
||||
* in a double-free.
|
||||
*/
|
||||
LLVMOrcJITStackRef LLVMOrcCreateInstance(LLVMTargetMachineRef TM);
|
||||
|
||||
/**
|
||||
* Get the error message for the most recent error (if any).
|
||||
*
|
||||
* This message is owned by the ORC JIT Stack and will be freed when the stack
|
||||
* is disposed of by LLVMOrcDisposeInstance.
|
||||
*/
|
||||
const char *LLVMOrcGetErrorMsg(LLVMOrcJITStackRef JITStack);
|
||||
|
||||
/**
|
||||
* Mangle the given symbol.
|
||||
* Memory will be allocated for MangledSymbol to hold the result. The client
|
||||
*/
|
||||
void LLVMOrcGetMangledSymbol(LLVMOrcJITStackRef JITStack, char **MangledSymbol,
|
||||
const char *Symbol);
|
||||
|
||||
/**
|
||||
* Dispose of a mangled symbol.
|
||||
*/
|
||||
void LLVMOrcDisposeMangledSymbol(char *MangledSymbol);
|
||||
|
||||
/**
|
||||
* Create a lazy compile callback.
|
||||
*/
|
||||
LLVMErrorRef LLVMOrcCreateLazyCompileCallback(
|
||||
LLVMOrcJITStackRef JITStack, LLVMOrcTargetAddress *RetAddr,
|
||||
LLVMOrcLazyCompileCallbackFn Callback, void *CallbackCtx);
|
||||
|
||||
/**
|
||||
* Create a named indirect call stub.
|
||||
*/
|
||||
LLVMErrorRef LLVMOrcCreateIndirectStub(LLVMOrcJITStackRef JITStack,
|
||||
const char *StubName,
|
||||
LLVMOrcTargetAddress InitAddr);
|
||||
|
||||
/**
|
||||
* Set the pointer for the given indirect stub.
|
||||
*/
|
||||
LLVMErrorRef LLVMOrcSetIndirectStubPointer(LLVMOrcJITStackRef JITStack,
|
||||
const char *StubName,
|
||||
LLVMOrcTargetAddress NewAddr);
|
||||
|
||||
/**
|
||||
* Add module to be eagerly compiled.
|
||||
*/
|
||||
LLVMErrorRef LLVMOrcAddEagerlyCompiledIR(LLVMOrcJITStackRef JITStack,
|
||||
LLVMOrcModuleHandle *RetHandle,
|
||||
LLVMModuleRef Mod,
|
||||
LLVMOrcSymbolResolverFn SymbolResolver,
|
||||
void *SymbolResolverCtx);
|
||||
|
||||
/**
|
||||
* Add module to be lazily compiled one function at a time.
|
||||
*/
|
||||
LLVMErrorRef LLVMOrcAddLazilyCompiledIR(LLVMOrcJITStackRef JITStack,
|
||||
LLVMOrcModuleHandle *RetHandle,
|
||||
LLVMModuleRef Mod,
|
||||
LLVMOrcSymbolResolverFn SymbolResolver,
|
||||
void *SymbolResolverCtx);
|
||||
|
||||
/**
|
||||
* Add an object file.
|
||||
*
|
||||
* This method takes ownership of the given memory buffer and attempts to add
|
||||
* it to the JIT as an object file.
|
||||
* Clients should *not* dispose of the 'Obj' argument: the JIT will manage it
|
||||
* from this call onwards.
|
||||
*/
|
||||
LLVMErrorRef LLVMOrcAddObjectFile(LLVMOrcJITStackRef JITStack,
|
||||
LLVMOrcModuleHandle *RetHandle,
|
||||
LLVMMemoryBufferRef Obj,
|
||||
LLVMOrcSymbolResolverFn SymbolResolver,
|
||||
void *SymbolResolverCtx);
|
||||
|
||||
/**
|
||||
* Remove a module set from the JIT.
|
||||
*
|
||||
* This works for all modules that can be added via OrcAdd*, including object
|
||||
* files.
|
||||
*/
|
||||
LLVMErrorRef LLVMOrcRemoveModule(LLVMOrcJITStackRef JITStack,
|
||||
LLVMOrcModuleHandle H);
|
||||
|
||||
/**
|
||||
* Get symbol address from JIT instance.
|
||||
*/
|
||||
LLVMErrorRef LLVMOrcGetSymbolAddress(LLVMOrcJITStackRef JITStack,
|
||||
LLVMOrcTargetAddress *RetAddr,
|
||||
const char *SymbolName);
|
||||
|
||||
/**
|
||||
* Get symbol address from JIT instance, searching only the specified
|
||||
* handle.
|
||||
*/
|
||||
LLVMErrorRef LLVMOrcGetSymbolAddressIn(LLVMOrcJITStackRef JITStack,
|
||||
LLVMOrcTargetAddress *RetAddr,
|
||||
LLVMOrcModuleHandle H,
|
||||
const char *SymbolName);
|
||||
|
||||
/**
|
||||
* Dispose of an ORC JIT stack.
|
||||
*/
|
||||
LLVMErrorRef LLVMOrcDisposeInstance(LLVMOrcJITStackRef JITStack);
|
||||
|
||||
/**
|
||||
* Register a JIT Event Listener.
|
||||
*
|
||||
* A NULL listener is ignored.
|
||||
*/
|
||||
void LLVMOrcRegisterJITEventListener(LLVMOrcJITStackRef JITStack, LLVMJITEventListenerRef L);
|
||||
|
||||
/**
|
||||
* Unegister a JIT Event Listener.
|
||||
*
|
||||
* A NULL listener is ignored.
|
||||
*/
|
||||
void LLVMOrcUnregisterJITEventListener(LLVMOrcJITStackRef JITStack, LLVMJITEventListenerRef L);
|
||||
|
||||
LLVM_C_EXTERN_C_END
|
||||
|
||||
#endif /* LLVM_C_ORCBINDINGS_H */
|
@ -142,11 +142,6 @@ protected:
|
||||
std::shared_ptr<LegacyJITSymbolResolver> SR,
|
||||
std::unique_ptr<TargetMachine> TM);
|
||||
|
||||
static ExecutionEngine *(*OrcMCJITReplacementCtor)(
|
||||
std::string *ErrorStr, std::shared_ptr<MCJITMemoryManager> MM,
|
||||
std::shared_ptr<LegacyJITSymbolResolver> SR,
|
||||
std::unique_ptr<TargetMachine> TM);
|
||||
|
||||
static ExecutionEngine *(*InterpCtor)(std::unique_ptr<Module> M,
|
||||
std::string *ErrorStr);
|
||||
|
||||
@ -552,7 +547,6 @@ private:
|
||||
std::string MCPU;
|
||||
SmallVector<std::string, 4> MAttrs;
|
||||
bool VerifyModules;
|
||||
bool UseOrcMCJITReplacement;
|
||||
bool EmulatedTLS = true;
|
||||
|
||||
public:
|
||||
@ -648,17 +642,6 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Use OrcMCJITReplacement instead of MCJIT. Off by default.
|
||||
LLVM_ATTRIBUTE_DEPRECATED(
|
||||
inline void setUseOrcMCJITReplacement(bool UseOrcMCJITReplacement),
|
||||
"ORCv1 utilities (including OrcMCJITReplacement) are deprecated. Please "
|
||||
"use ORCv2/LLJIT instead (see docs/ORCv2.rst)");
|
||||
|
||||
void setUseOrcMCJITReplacement(ORCv1DeprecationAcknowledgement,
|
||||
bool UseOrcMCJITReplacement) {
|
||||
this->UseOrcMCJITReplacement = UseOrcMCJITReplacement;
|
||||
}
|
||||
|
||||
void setEmulatedTLS(bool EmulatedTLS) {
|
||||
this->EmulatedTLS = EmulatedTLS;
|
||||
}
|
||||
@ -679,10 +662,6 @@ public:
|
||||
ExecutionEngine *create(TargetMachine *TM);
|
||||
};
|
||||
|
||||
void EngineBuilder::setUseOrcMCJITReplacement(bool UseOrcMCJITReplacement) {
|
||||
this->UseOrcMCJITReplacement = UseOrcMCJITReplacement;
|
||||
}
|
||||
|
||||
// Create wrappers for C Binding types (see CBindingWrapping.h).
|
||||
DEFINE_SIMPLE_CONVERSION_FUNCTIONS(ExecutionEngine, LLVMExecutionEngineRef)
|
||||
|
||||
|
@ -20,10 +20,8 @@
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/ExecutionEngine/JITSymbol.h"
|
||||
#include "llvm/ExecutionEngine/Orc/IndirectionUtils.h"
|
||||
#include "llvm/ExecutionEngine/Orc/LambdaResolver.h"
|
||||
#include "llvm/ExecutionEngine/Orc/Layer.h"
|
||||
#include "llvm/ExecutionEngine/Orc/LazyReexports.h"
|
||||
#include "llvm/ExecutionEngine/Orc/Legacy.h"
|
||||
#include "llvm/ExecutionEngine/Orc/OrcError.h"
|
||||
#include "llvm/ExecutionEngine/Orc/Speculation.h"
|
||||
#include "llvm/ExecutionEngine/RuntimeDyld.h"
|
||||
@ -136,635 +134,6 @@ private:
|
||||
ImplSymbolMap *AliaseeImpls = nullptr;
|
||||
};
|
||||
|
||||
/// Compile-on-demand layer.
|
||||
///
|
||||
/// When a module is added to this layer a stub is created for each of its
|
||||
/// function definitions. The stubs and other global values are immediately
|
||||
/// added to the layer below. When a stub is called it triggers the extraction
|
||||
/// of the function body from the original module. The extracted body is then
|
||||
/// compiled and executed.
|
||||
template <typename BaseLayerT,
|
||||
typename CompileCallbackMgrT = JITCompileCallbackManager,
|
||||
typename IndirectStubsMgrT = IndirectStubsManager>
|
||||
class LegacyCompileOnDemandLayer {
|
||||
private:
|
||||
template <typename MaterializerFtor>
|
||||
class LambdaMaterializer final : public ValueMaterializer {
|
||||
public:
|
||||
LambdaMaterializer(MaterializerFtor M) : M(std::move(M)) {}
|
||||
|
||||
Value *materialize(Value *V) final { return M(V); }
|
||||
|
||||
private:
|
||||
MaterializerFtor M;
|
||||
};
|
||||
|
||||
template <typename MaterializerFtor>
|
||||
LambdaMaterializer<MaterializerFtor>
|
||||
createLambdaMaterializer(MaterializerFtor M) {
|
||||
return LambdaMaterializer<MaterializerFtor>(std::move(M));
|
||||
}
|
||||
|
||||
// Provide type-erasure for the Modules and MemoryManagers.
|
||||
template <typename ResourceT>
|
||||
class ResourceOwner {
|
||||
public:
|
||||
ResourceOwner() = default;
|
||||
ResourceOwner(const ResourceOwner &) = delete;
|
||||
ResourceOwner &operator=(const ResourceOwner &) = delete;
|
||||
virtual ~ResourceOwner() = default;
|
||||
|
||||
virtual ResourceT& getResource() const = 0;
|
||||
};
|
||||
|
||||
template <typename ResourceT, typename ResourcePtrT>
|
||||
class ResourceOwnerImpl : public ResourceOwner<ResourceT> {
|
||||
public:
|
||||
ResourceOwnerImpl(ResourcePtrT ResourcePtr)
|
||||
: ResourcePtr(std::move(ResourcePtr)) {}
|
||||
|
||||
ResourceT& getResource() const override { return *ResourcePtr; }
|
||||
|
||||
private:
|
||||
ResourcePtrT ResourcePtr;
|
||||
};
|
||||
|
||||
template <typename ResourceT, typename ResourcePtrT>
|
||||
std::unique_ptr<ResourceOwner<ResourceT>>
|
||||
wrapOwnership(ResourcePtrT ResourcePtr) {
|
||||
using RO = ResourceOwnerImpl<ResourceT, ResourcePtrT>;
|
||||
return std::make_unique<RO>(std::move(ResourcePtr));
|
||||
}
|
||||
|
||||
struct LogicalDylib {
|
||||
struct SourceModuleEntry {
|
||||
std::unique_ptr<Module> SourceMod;
|
||||
std::set<Function*> StubsToClone;
|
||||
};
|
||||
|
||||
using SourceModulesList = std::vector<SourceModuleEntry>;
|
||||
using SourceModuleHandle = typename SourceModulesList::size_type;
|
||||
|
||||
LogicalDylib() = default;
|
||||
|
||||
LogicalDylib(VModuleKey K, std::shared_ptr<SymbolResolver> BackingResolver,
|
||||
std::unique_ptr<IndirectStubsMgrT> StubsMgr)
|
||||
: K(std::move(K)), BackingResolver(std::move(BackingResolver)),
|
||||
StubsMgr(std::move(StubsMgr)) {}
|
||||
|
||||
SourceModuleHandle addSourceModule(std::unique_ptr<Module> M) {
|
||||
SourceModuleHandle H = SourceModules.size();
|
||||
SourceModules.push_back(SourceModuleEntry());
|
||||
SourceModules.back().SourceMod = std::move(M);
|
||||
return H;
|
||||
}
|
||||
|
||||
Module& getSourceModule(SourceModuleHandle H) {
|
||||
return *SourceModules[H].SourceMod;
|
||||
}
|
||||
|
||||
std::set<Function*>& getStubsToClone(SourceModuleHandle H) {
|
||||
return SourceModules[H].StubsToClone;
|
||||
}
|
||||
|
||||
JITSymbol findSymbol(BaseLayerT &BaseLayer, const std::string &Name,
|
||||
bool ExportedSymbolsOnly) {
|
||||
if (auto Sym = StubsMgr->findStub(Name, ExportedSymbolsOnly))
|
||||
return Sym;
|
||||
for (auto BLK : BaseLayerVModuleKeys)
|
||||
if (auto Sym = BaseLayer.findSymbolIn(BLK, Name, ExportedSymbolsOnly))
|
||||
return Sym;
|
||||
else if (auto Err = Sym.takeError())
|
||||
return std::move(Err);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Error removeModulesFromBaseLayer(BaseLayerT &BaseLayer) {
|
||||
for (auto &BLK : BaseLayerVModuleKeys)
|
||||
if (auto Err = BaseLayer.removeModule(BLK))
|
||||
return Err;
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
VModuleKey K;
|
||||
std::shared_ptr<SymbolResolver> BackingResolver;
|
||||
std::unique_ptr<IndirectStubsMgrT> StubsMgr;
|
||||
SymbolLinkagePromoter PromoteSymbols;
|
||||
SourceModulesList SourceModules;
|
||||
std::vector<VModuleKey> BaseLayerVModuleKeys;
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
/// Module partitioning functor.
|
||||
using PartitioningFtor = std::function<std::set<Function*>(Function&)>;
|
||||
|
||||
/// Builder for IndirectStubsManagers.
|
||||
using IndirectStubsManagerBuilderT =
|
||||
std::function<std::unique_ptr<IndirectStubsMgrT>()>;
|
||||
|
||||
using SymbolResolverGetter =
|
||||
std::function<std::shared_ptr<SymbolResolver>(VModuleKey K)>;
|
||||
|
||||
using SymbolResolverSetter =
|
||||
std::function<void(VModuleKey K, std::shared_ptr<SymbolResolver> R)>;
|
||||
|
||||
/// Construct a compile-on-demand layer instance.
|
||||
LLVM_ATTRIBUTE_DEPRECATED(
|
||||
LegacyCompileOnDemandLayer(
|
||||
ExecutionSession &ES, BaseLayerT &BaseLayer,
|
||||
SymbolResolverGetter GetSymbolResolver,
|
||||
SymbolResolverSetter SetSymbolResolver, PartitioningFtor Partition,
|
||||
CompileCallbackMgrT &CallbackMgr,
|
||||
IndirectStubsManagerBuilderT CreateIndirectStubsManager,
|
||||
bool CloneStubsIntoPartitions = true),
|
||||
"ORCv1 layers (layers with the 'Legacy' prefix) are deprecated. Please "
|
||||
"use "
|
||||
"the ORCv2 LegacyCompileOnDemandLayer instead");
|
||||
|
||||
/// Legacy layer constructor with deprecation acknowledgement.
|
||||
LegacyCompileOnDemandLayer(
|
||||
ORCv1DeprecationAcknowledgement, ExecutionSession &ES,
|
||||
BaseLayerT &BaseLayer, SymbolResolverGetter GetSymbolResolver,
|
||||
SymbolResolverSetter SetSymbolResolver, PartitioningFtor Partition,
|
||||
CompileCallbackMgrT &CallbackMgr,
|
||||
IndirectStubsManagerBuilderT CreateIndirectStubsManager,
|
||||
bool CloneStubsIntoPartitions = true)
|
||||
: ES(ES), BaseLayer(BaseLayer),
|
||||
GetSymbolResolver(std::move(GetSymbolResolver)),
|
||||
SetSymbolResolver(std::move(SetSymbolResolver)),
|
||||
Partition(std::move(Partition)), CompileCallbackMgr(CallbackMgr),
|
||||
CreateIndirectStubsManager(std::move(CreateIndirectStubsManager)),
|
||||
CloneStubsIntoPartitions(CloneStubsIntoPartitions) {}
|
||||
|
||||
~LegacyCompileOnDemandLayer() {
|
||||
// FIXME: Report error on log.
|
||||
while (!LogicalDylibs.empty())
|
||||
consumeError(removeModule(LogicalDylibs.begin()->first));
|
||||
}
|
||||
|
||||
/// Add a module to the compile-on-demand layer.
|
||||
Error addModule(VModuleKey K, std::unique_ptr<Module> M) {
|
||||
|
||||
assert(!LogicalDylibs.count(K) && "VModuleKey K already in use");
|
||||
auto I = LogicalDylibs.insert(
|
||||
LogicalDylibs.end(),
|
||||
std::make_pair(K, LogicalDylib(K, GetSymbolResolver(K),
|
||||
CreateIndirectStubsManager())));
|
||||
|
||||
return addLogicalModule(I->second, std::move(M));
|
||||
}
|
||||
|
||||
/// Add extra modules to an existing logical module.
|
||||
Error addExtraModule(VModuleKey K, std::unique_ptr<Module> M) {
|
||||
return addLogicalModule(LogicalDylibs[K], std::move(M));
|
||||
}
|
||||
|
||||
/// Remove the module represented by the given key.
|
||||
///
|
||||
/// This will remove all modules in the layers below that were derived from
|
||||
/// the module represented by K.
|
||||
Error removeModule(VModuleKey K) {
|
||||
auto I = LogicalDylibs.find(K);
|
||||
assert(I != LogicalDylibs.end() && "VModuleKey K not valid here");
|
||||
auto Err = I->second.removeModulesFromBaseLayer(BaseLayer);
|
||||
LogicalDylibs.erase(I);
|
||||
return Err;
|
||||
}
|
||||
|
||||
/// Search for the given named symbol.
|
||||
/// @param Name The name of the symbol to search for.
|
||||
/// @param ExportedSymbolsOnly If true, search only for exported symbols.
|
||||
/// @return A handle for the given named symbol, if it exists.
|
||||
JITSymbol findSymbol(StringRef Name, bool ExportedSymbolsOnly) {
|
||||
for (auto &KV : LogicalDylibs) {
|
||||
if (auto Sym = KV.second.StubsMgr->findStub(Name, ExportedSymbolsOnly))
|
||||
return Sym;
|
||||
if (auto Sym =
|
||||
findSymbolIn(KV.first, std::string(Name), ExportedSymbolsOnly))
|
||||
return Sym;
|
||||
else if (auto Err = Sym.takeError())
|
||||
return std::move(Err);
|
||||
}
|
||||
return BaseLayer.findSymbol(std::string(Name), ExportedSymbolsOnly);
|
||||
}
|
||||
|
||||
/// Get the address of a symbol provided by this layer, or some layer
|
||||
/// below this one.
|
||||
JITSymbol findSymbolIn(VModuleKey K, const std::string &Name,
|
||||
bool ExportedSymbolsOnly) {
|
||||
assert(LogicalDylibs.count(K) && "VModuleKey K is not valid here");
|
||||
return LogicalDylibs[K].findSymbol(BaseLayer, Name, ExportedSymbolsOnly);
|
||||
}
|
||||
|
||||
/// Update the stub for the given function to point at FnBodyAddr.
|
||||
/// This can be used to support re-optimization.
|
||||
/// @return true if the function exists and the stub is updated, false
|
||||
/// otherwise.
|
||||
//
|
||||
// FIXME: We should track and free associated resources (unused compile
|
||||
// callbacks, uncompiled IR, and no-longer-needed/reachable function
|
||||
// implementations).
|
||||
Error updatePointer(std::string FuncName, JITTargetAddress FnBodyAddr) {
|
||||
//Find out which logical dylib contains our symbol
|
||||
auto LDI = LogicalDylibs.begin();
|
||||
for (auto LDE = LogicalDylibs.end(); LDI != LDE; ++LDI) {
|
||||
if (auto LMResources =
|
||||
LDI->getLogicalModuleResourcesForSymbol(FuncName, false)) {
|
||||
Module &SrcM = LMResources->SourceModule->getResource();
|
||||
std::string CalledFnName = mangle(FuncName, SrcM.getDataLayout());
|
||||
if (auto Err = LMResources->StubsMgr->updatePointer(CalledFnName,
|
||||
FnBodyAddr))
|
||||
return Err;
|
||||
return Error::success();
|
||||
}
|
||||
}
|
||||
return make_error<JITSymbolNotFound>(FuncName);
|
||||
}
|
||||
|
||||
private:
|
||||
Error addLogicalModule(LogicalDylib &LD, std::unique_ptr<Module> SrcMPtr) {
|
||||
|
||||
// Rename anonymous globals and promote linkage to ensure that everything
|
||||
// will resolve properly after we partition SrcM.
|
||||
LD.PromoteSymbols(*SrcMPtr);
|
||||
|
||||
// Create a logical module handle for SrcM within the logical dylib.
|
||||
Module &SrcM = *SrcMPtr;
|
||||
auto LMId = LD.addSourceModule(std::move(SrcMPtr));
|
||||
|
||||
// Create stub functions.
|
||||
const DataLayout &DL = SrcM.getDataLayout();
|
||||
|
||||
typename IndirectStubsMgrT::StubInitsMap StubInits;
|
||||
for (auto &F : SrcM) {
|
||||
// Skip declarations.
|
||||
if (F.isDeclaration())
|
||||
continue;
|
||||
|
||||
// Skip weak functions for which we already have definitions.
|
||||
auto MangledName = mangle(F.getName(), DL);
|
||||
if (F.hasWeakLinkage() || F.hasLinkOnceLinkage()) {
|
||||
if (auto Sym = LD.findSymbol(BaseLayer, MangledName, false))
|
||||
continue;
|
||||
else if (auto Err = Sym.takeError())
|
||||
return Err;
|
||||
}
|
||||
|
||||
// Record all functions defined by this module.
|
||||
if (CloneStubsIntoPartitions)
|
||||
LD.getStubsToClone(LMId).insert(&F);
|
||||
|
||||
// Create a callback, associate it with the stub for the function,
|
||||
// and set the compile action to compile the partition containing the
|
||||
// function.
|
||||
auto CompileAction = [this, &LD, LMId, &F]() -> JITTargetAddress {
|
||||
if (auto FnImplAddrOrErr = this->extractAndCompile(LD, LMId, F))
|
||||
return *FnImplAddrOrErr;
|
||||
else {
|
||||
// FIXME: Report error, return to 'abort' or something similar.
|
||||
consumeError(FnImplAddrOrErr.takeError());
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
if (auto CCAddr =
|
||||
CompileCallbackMgr.getCompileCallback(std::move(CompileAction)))
|
||||
StubInits[MangledName] =
|
||||
std::make_pair(*CCAddr, JITSymbolFlags::fromGlobalValue(F));
|
||||
else
|
||||
return CCAddr.takeError();
|
||||
}
|
||||
|
||||
if (auto Err = LD.StubsMgr->createStubs(StubInits))
|
||||
return Err;
|
||||
|
||||
// If this module doesn't contain any globals, aliases, or module flags then
|
||||
// we can bail out early and avoid the overhead of creating and managing an
|
||||
// empty globals module.
|
||||
if (SrcM.global_empty() && SrcM.alias_empty() &&
|
||||
!SrcM.getModuleFlagsMetadata())
|
||||
return Error::success();
|
||||
|
||||
// Create the GlobalValues module.
|
||||
auto GVsM = std::make_unique<Module>((SrcM.getName() + ".globals").str(),
|
||||
SrcM.getContext());
|
||||
GVsM->setDataLayout(DL);
|
||||
|
||||
ValueToValueMapTy VMap;
|
||||
|
||||
// Clone global variable decls.
|
||||
for (auto &GV : SrcM.globals())
|
||||
if (!GV.isDeclaration() && !VMap.count(&GV))
|
||||
cloneGlobalVariableDecl(*GVsM, GV, &VMap);
|
||||
|
||||
// And the aliases.
|
||||
for (auto &A : SrcM.aliases())
|
||||
if (!VMap.count(&A))
|
||||
cloneGlobalAliasDecl(*GVsM, A, VMap);
|
||||
|
||||
// Clone the module flags.
|
||||
cloneModuleFlagsMetadata(*GVsM, SrcM, VMap);
|
||||
|
||||
// Now we need to clone the GV and alias initializers.
|
||||
|
||||
// Initializers may refer to functions declared (but not defined) in this
|
||||
// module. Build a materializer to clone decls on demand.
|
||||
auto Materializer = createLambdaMaterializer(
|
||||
[&LD, &GVsM](Value *V) -> Value* {
|
||||
if (auto *F = dyn_cast<Function>(V)) {
|
||||
// Decls in the original module just get cloned.
|
||||
if (F->isDeclaration())
|
||||
return cloneFunctionDecl(*GVsM, *F);
|
||||
|
||||
// Definitions in the original module (which we have emitted stubs
|
||||
// for at this point) get turned into a constant alias to the stub
|
||||
// instead.
|
||||
const DataLayout &DL = GVsM->getDataLayout();
|
||||
std::string FName = mangle(F->getName(), DL);
|
||||
unsigned PtrBitWidth = DL.getPointerTypeSizeInBits(F->getType());
|
||||
JITTargetAddress StubAddr =
|
||||
LD.StubsMgr->findStub(FName, false).getAddress();
|
||||
|
||||
ConstantInt *StubAddrCI =
|
||||
ConstantInt::get(GVsM->getContext(), APInt(PtrBitWidth, StubAddr));
|
||||
Constant *Init = ConstantExpr::getCast(Instruction::IntToPtr,
|
||||
StubAddrCI, F->getType());
|
||||
return GlobalAlias::create(F->getFunctionType(),
|
||||
F->getType()->getAddressSpace(),
|
||||
F->getLinkage(), F->getName(),
|
||||
Init, GVsM.get());
|
||||
}
|
||||
// else....
|
||||
return nullptr;
|
||||
});
|
||||
|
||||
// Clone the global variable initializers.
|
||||
for (auto &GV : SrcM.globals())
|
||||
if (!GV.isDeclaration())
|
||||
moveGlobalVariableInitializer(GV, VMap, &Materializer);
|
||||
|
||||
// Clone the global alias initializers.
|
||||
for (auto &A : SrcM.aliases()) {
|
||||
auto *NewA = cast<GlobalAlias>(VMap[&A]);
|
||||
assert(NewA && "Alias not cloned?");
|
||||
Value *Init = MapValue(A.getAliasee(), VMap, RF_None, nullptr,
|
||||
&Materializer);
|
||||
NewA->setAliasee(cast<Constant>(Init));
|
||||
}
|
||||
|
||||
// Build a resolver for the globals module and add it to the base layer.
|
||||
auto LegacyLookup = [this, &LD](StringRef Name) -> JITSymbol {
|
||||
if (auto Sym = LD.StubsMgr->findStub(Name, false))
|
||||
return Sym;
|
||||
|
||||
if (auto Sym = LD.findSymbol(BaseLayer, std::string(Name), false))
|
||||
return Sym;
|
||||
else if (auto Err = Sym.takeError())
|
||||
return std::move(Err);
|
||||
|
||||
return nullptr;
|
||||
};
|
||||
|
||||
auto GVsResolver = createSymbolResolver(
|
||||
[&LD, LegacyLookup](const SymbolNameSet &Symbols) {
|
||||
auto RS = getResponsibilitySetWithLegacyFn(Symbols, LegacyLookup);
|
||||
|
||||
if (!RS) {
|
||||
logAllUnhandledErrors(
|
||||
RS.takeError(), errs(),
|
||||
"CODLayer/GVsResolver responsibility set lookup failed: ");
|
||||
return SymbolNameSet();
|
||||
}
|
||||
|
||||
if (RS->size() == Symbols.size())
|
||||
return *RS;
|
||||
|
||||
SymbolNameSet NotFoundViaLegacyLookup;
|
||||
for (auto &S : Symbols)
|
||||
if (!RS->count(S))
|
||||
NotFoundViaLegacyLookup.insert(S);
|
||||
auto RS2 =
|
||||
LD.BackingResolver->getResponsibilitySet(NotFoundViaLegacyLookup);
|
||||
|
||||
for (auto &S : RS2)
|
||||
(*RS).insert(S);
|
||||
|
||||
return *RS;
|
||||
},
|
||||
[this, &LD,
|
||||
LegacyLookup](std::shared_ptr<AsynchronousSymbolQuery> Query,
|
||||
SymbolNameSet Symbols) {
|
||||
auto NotFoundViaLegacyLookup =
|
||||
lookupWithLegacyFn(ES, *Query, Symbols, LegacyLookup);
|
||||
return LD.BackingResolver->lookup(Query, NotFoundViaLegacyLookup);
|
||||
});
|
||||
|
||||
SetSymbolResolver(LD.K, std::move(GVsResolver));
|
||||
|
||||
if (auto Err = BaseLayer.addModule(LD.K, std::move(GVsM)))
|
||||
return Err;
|
||||
|
||||
LD.BaseLayerVModuleKeys.push_back(LD.K);
|
||||
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
static std::string mangle(StringRef Name, const DataLayout &DL) {
|
||||
std::string MangledName;
|
||||
{
|
||||
raw_string_ostream MangledNameStream(MangledName);
|
||||
Mangler::getNameWithPrefix(MangledNameStream, Name, DL);
|
||||
}
|
||||
return MangledName;
|
||||
}
|
||||
|
||||
Expected<JITTargetAddress>
|
||||
extractAndCompile(LogicalDylib &LD,
|
||||
typename LogicalDylib::SourceModuleHandle LMId,
|
||||
Function &F) {
|
||||
Module &SrcM = LD.getSourceModule(LMId);
|
||||
|
||||
// If F is a declaration we must already have compiled it.
|
||||
if (F.isDeclaration())
|
||||
return 0;
|
||||
|
||||
// Grab the name of the function being called here.
|
||||
std::string CalledFnName = mangle(F.getName(), SrcM.getDataLayout());
|
||||
|
||||
JITTargetAddress CalledAddr = 0;
|
||||
auto Part = Partition(F);
|
||||
if (auto PartKeyOrErr = emitPartition(LD, LMId, Part)) {
|
||||
auto &PartKey = *PartKeyOrErr;
|
||||
for (auto *SubF : Part) {
|
||||
std::string FnName = mangle(SubF->getName(), SrcM.getDataLayout());
|
||||
if (auto FnBodySym = BaseLayer.findSymbolIn(PartKey, FnName, false)) {
|
||||
if (auto FnBodyAddrOrErr = FnBodySym.getAddress()) {
|
||||
JITTargetAddress FnBodyAddr = *FnBodyAddrOrErr;
|
||||
|
||||
// If this is the function we're calling record the address so we can
|
||||
// return it from this function.
|
||||
if (SubF == &F)
|
||||
CalledAddr = FnBodyAddr;
|
||||
|
||||
// Update the function body pointer for the stub.
|
||||
if (auto EC = LD.StubsMgr->updatePointer(FnName, FnBodyAddr))
|
||||
return 0;
|
||||
|
||||
} else
|
||||
return FnBodyAddrOrErr.takeError();
|
||||
} else if (auto Err = FnBodySym.takeError())
|
||||
return std::move(Err);
|
||||
else
|
||||
llvm_unreachable("Function not emitted for partition");
|
||||
}
|
||||
|
||||
LD.BaseLayerVModuleKeys.push_back(PartKey);
|
||||
} else
|
||||
return PartKeyOrErr.takeError();
|
||||
|
||||
return CalledAddr;
|
||||
}
|
||||
|
||||
template <typename PartitionT>
|
||||
Expected<VModuleKey>
|
||||
emitPartition(LogicalDylib &LD,
|
||||
typename LogicalDylib::SourceModuleHandle LMId,
|
||||
const PartitionT &Part) {
|
||||
Module &SrcM = LD.getSourceModule(LMId);
|
||||
|
||||
// Create the module.
|
||||
std::string NewName(SrcM.getName());
|
||||
for (auto *F : Part) {
|
||||
NewName += ".";
|
||||
NewName += F->getName();
|
||||
}
|
||||
|
||||
auto M = std::make_unique<Module>(NewName, SrcM.getContext());
|
||||
M->setDataLayout(SrcM.getDataLayout());
|
||||
ValueToValueMapTy VMap;
|
||||
|
||||
auto Materializer = createLambdaMaterializer([&LD, &LMId,
|
||||
&M](Value *V) -> Value * {
|
||||
if (auto *GV = dyn_cast<GlobalVariable>(V))
|
||||
return cloneGlobalVariableDecl(*M, *GV);
|
||||
|
||||
if (auto *F = dyn_cast<Function>(V)) {
|
||||
// Check whether we want to clone an available_externally definition.
|
||||
if (!LD.getStubsToClone(LMId).count(F))
|
||||
return cloneFunctionDecl(*M, *F);
|
||||
|
||||
// Ok - we want an inlinable stub. For that to work we need a decl
|
||||
// for the stub pointer.
|
||||
auto *StubPtr = createImplPointer(*F->getType(), *M,
|
||||
F->getName() + "$stub_ptr", nullptr);
|
||||
auto *ClonedF = cloneFunctionDecl(*M, *F);
|
||||
makeStub(*ClonedF, *StubPtr);
|
||||
ClonedF->setLinkage(GlobalValue::AvailableExternallyLinkage);
|
||||
ClonedF->addFnAttr(Attribute::AlwaysInline);
|
||||
return ClonedF;
|
||||
}
|
||||
|
||||
if (auto *A = dyn_cast<GlobalAlias>(V)) {
|
||||
auto *Ty = A->getValueType();
|
||||
if (Ty->isFunctionTy())
|
||||
return Function::Create(cast<FunctionType>(Ty),
|
||||
GlobalValue::ExternalLinkage, A->getName(),
|
||||
M.get());
|
||||
|
||||
return new GlobalVariable(*M, Ty, false, GlobalValue::ExternalLinkage,
|
||||
nullptr, A->getName(), nullptr,
|
||||
GlobalValue::NotThreadLocal,
|
||||
A->getType()->getAddressSpace());
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
});
|
||||
|
||||
// Create decls in the new module.
|
||||
for (auto *F : Part)
|
||||
cloneFunctionDecl(*M, *F, &VMap);
|
||||
|
||||
// Move the function bodies.
|
||||
for (auto *F : Part)
|
||||
moveFunctionBody(*F, VMap, &Materializer);
|
||||
|
||||
auto K = ES.allocateVModule();
|
||||
|
||||
auto LegacyLookup = [this, &LD](StringRef Name) -> JITSymbol {
|
||||
return LD.findSymbol(BaseLayer, std::string(Name), false);
|
||||
};
|
||||
|
||||
// Create memory manager and symbol resolver.
|
||||
auto Resolver = createSymbolResolver(
|
||||
[&LD, LegacyLookup](const SymbolNameSet &Symbols) {
|
||||
auto RS = getResponsibilitySetWithLegacyFn(Symbols, LegacyLookup);
|
||||
if (!RS) {
|
||||
logAllUnhandledErrors(
|
||||
RS.takeError(), errs(),
|
||||
"CODLayer/SubResolver responsibility set lookup failed: ");
|
||||
return SymbolNameSet();
|
||||
}
|
||||
|
||||
if (RS->size() == Symbols.size())
|
||||
return *RS;
|
||||
|
||||
SymbolNameSet NotFoundViaLegacyLookup;
|
||||
for (auto &S : Symbols)
|
||||
if (!RS->count(S))
|
||||
NotFoundViaLegacyLookup.insert(S);
|
||||
|
||||
auto RS2 =
|
||||
LD.BackingResolver->getResponsibilitySet(NotFoundViaLegacyLookup);
|
||||
|
||||
for (auto &S : RS2)
|
||||
(*RS).insert(S);
|
||||
|
||||
return *RS;
|
||||
},
|
||||
[this, &LD, LegacyLookup](std::shared_ptr<AsynchronousSymbolQuery> Q,
|
||||
SymbolNameSet Symbols) {
|
||||
auto NotFoundViaLegacyLookup =
|
||||
lookupWithLegacyFn(ES, *Q, Symbols, LegacyLookup);
|
||||
return LD.BackingResolver->lookup(Q,
|
||||
std::move(NotFoundViaLegacyLookup));
|
||||
});
|
||||
SetSymbolResolver(K, std::move(Resolver));
|
||||
|
||||
if (auto Err = BaseLayer.addModule(std::move(K), std::move(M)))
|
||||
return std::move(Err);
|
||||
|
||||
return K;
|
||||
}
|
||||
|
||||
ExecutionSession &ES;
|
||||
BaseLayerT &BaseLayer;
|
||||
SymbolResolverGetter GetSymbolResolver;
|
||||
SymbolResolverSetter SetSymbolResolver;
|
||||
PartitioningFtor Partition;
|
||||
CompileCallbackMgrT &CompileCallbackMgr;
|
||||
IndirectStubsManagerBuilderT CreateIndirectStubsManager;
|
||||
|
||||
std::map<VModuleKey, LogicalDylib> LogicalDylibs;
|
||||
bool CloneStubsIntoPartitions;
|
||||
};
|
||||
|
||||
template <typename BaseLayerT, typename CompileCallbackMgrT,
|
||||
typename IndirectStubsMgrT>
|
||||
LegacyCompileOnDemandLayer<BaseLayerT, CompileCallbackMgrT, IndirectStubsMgrT>::
|
||||
LegacyCompileOnDemandLayer(
|
||||
ExecutionSession &ES, BaseLayerT &BaseLayer,
|
||||
SymbolResolverGetter GetSymbolResolver,
|
||||
SymbolResolverSetter SetSymbolResolver, PartitioningFtor Partition,
|
||||
CompileCallbackMgrT &CallbackMgr,
|
||||
IndirectStubsManagerBuilderT CreateIndirectStubsManager,
|
||||
bool CloneStubsIntoPartitions)
|
||||
: ES(ES), BaseLayer(BaseLayer),
|
||||
GetSymbolResolver(std::move(GetSymbolResolver)),
|
||||
SetSymbolResolver(std::move(SetSymbolResolver)),
|
||||
Partition(std::move(Partition)), CompileCallbackMgr(CallbackMgr),
|
||||
CreateIndirectStubsManager(std::move(CreateIndirectStubsManager)),
|
||||
CloneStubsIntoPartitions(CloneStubsIntoPartitions) {}
|
||||
|
||||
} // end namespace orc
|
||||
} // end namespace llvm
|
||||
|
||||
|
@ -759,8 +759,6 @@ private:
|
||||
|
||||
void dropSymbol(const SymbolStringPtr &Name);
|
||||
|
||||
bool canStillFail();
|
||||
|
||||
void handleFailed(Error Err);
|
||||
|
||||
void detach();
|
||||
@ -912,17 +910,6 @@ public:
|
||||
/// Dump current JITDylib state to OS.
|
||||
void dump(raw_ostream &OS);
|
||||
|
||||
/// FIXME: Remove this when we remove the old ORC layers.
|
||||
/// Search the given JITDylibs in order for the symbols in Symbols. Results
|
||||
/// (once they become available) will be returned via the given Query.
|
||||
///
|
||||
/// If any symbol is not found then the unresolved symbols will be returned,
|
||||
/// and the query will not be applied. The Query is not failed and can be
|
||||
/// re-used in a subsequent lookup once the symbols have been added, or
|
||||
/// manually failed.
|
||||
Expected<SymbolNameSet>
|
||||
legacyLookup(std::shared_ptr<AsynchronousSymbolQuery> Q, SymbolNameSet Names);
|
||||
|
||||
/// Returns the given JITDylibs and all of their transitive dependencies in
|
||||
/// DFS order (based on linkage relationships). Each JITDylib will appear
|
||||
/// only once.
|
||||
@ -1039,10 +1026,6 @@ private:
|
||||
LookupKind K, JITDylibLookupFlags JDLookupFlags,
|
||||
SymbolLookupSet &Unresolved);
|
||||
|
||||
bool lookupImpl(std::shared_ptr<AsynchronousSymbolQuery> &Q,
|
||||
std::vector<std::unique_ptr<MaterializationUnit>> &MUs,
|
||||
SymbolLookupSet &Unresolved);
|
||||
|
||||
void detachQueryHelper(AsynchronousSymbolQuery &Q,
|
||||
const SymbolNameSet &QuerySymbols);
|
||||
|
||||
@ -1198,18 +1181,6 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
void legacyFailQuery(AsynchronousSymbolQuery &Q, Error Err);
|
||||
|
||||
using LegacyAsyncLookupFunction = std::function<SymbolNameSet(
|
||||
std::shared_ptr<AsynchronousSymbolQuery> Q, SymbolNameSet Names)>;
|
||||
|
||||
/// A legacy lookup function for JITSymbolResolverAdapter.
|
||||
/// Do not use -- this will be removed soon.
|
||||
Expected<SymbolMap>
|
||||
legacyLookup(LegacyAsyncLookupFunction AsyncLookup, SymbolNameSet Names,
|
||||
SymbolState RequiredState,
|
||||
RegisterDependenciesFunction RegisterDependencies);
|
||||
|
||||
/// Search the given JITDylib list for the given symbols.
|
||||
///
|
||||
/// SearchOrder lists the JITDylibs to search. For each dylib, the associated
|
||||
|
@ -152,56 +152,6 @@ inline iterator_range<StaticInitGVIterator> getStaticInitGVs(Module &M) {
|
||||
return make_range(StaticInitGVIterator(M), StaticInitGVIterator());
|
||||
}
|
||||
|
||||
/// Convenience class for recording constructor/destructor names for
|
||||
/// later execution.
|
||||
template <typename JITLayerT>
|
||||
class LegacyCtorDtorRunner {
|
||||
public:
|
||||
/// Construct a CtorDtorRunner for the given range using the given
|
||||
/// name mangling function.
|
||||
LLVM_ATTRIBUTE_DEPRECATED(
|
||||
LegacyCtorDtorRunner(std::vector<std::string> CtorDtorNames,
|
||||
VModuleKey K),
|
||||
"ORCv1 utilities (utilities with the 'Legacy' prefix) are deprecated. "
|
||||
"Please use the ORCv2 CtorDtorRunner utility instead");
|
||||
|
||||
LegacyCtorDtorRunner(ORCv1DeprecationAcknowledgement,
|
||||
std::vector<std::string> CtorDtorNames, VModuleKey K)
|
||||
: CtorDtorNames(std::move(CtorDtorNames)), K(K) {}
|
||||
|
||||
/// Run the recorded constructors/destructors through the given JIT
|
||||
/// layer.
|
||||
Error runViaLayer(JITLayerT &JITLayer) const {
|
||||
using CtorDtorTy = void (*)();
|
||||
|
||||
for (const auto &CtorDtorName : CtorDtorNames) {
|
||||
if (auto CtorDtorSym = JITLayer.findSymbolIn(K, CtorDtorName, false)) {
|
||||
if (auto AddrOrErr = CtorDtorSym.getAddress()) {
|
||||
CtorDtorTy CtorDtor =
|
||||
reinterpret_cast<CtorDtorTy>(static_cast<uintptr_t>(*AddrOrErr));
|
||||
CtorDtor();
|
||||
} else
|
||||
return AddrOrErr.takeError();
|
||||
} else {
|
||||
if (auto Err = CtorDtorSym.takeError())
|
||||
return Err;
|
||||
else
|
||||
return make_error<JITSymbolNotFound>(CtorDtorName);
|
||||
}
|
||||
}
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<std::string> CtorDtorNames;
|
||||
orc::VModuleKey K;
|
||||
};
|
||||
|
||||
template <typename JITLayerT>
|
||||
LegacyCtorDtorRunner<JITLayerT>::LegacyCtorDtorRunner(
|
||||
std::vector<std::string> CtorDtorNames, VModuleKey K)
|
||||
: CtorDtorNames(std::move(CtorDtorNames)), K(K) {}
|
||||
|
||||
class CtorDtorRunner {
|
||||
public:
|
||||
CtorDtorRunner(JITDylib &JD) : JD(JD) {}
|
||||
@ -250,45 +200,6 @@ protected:
|
||||
void *DSOHandle);
|
||||
};
|
||||
|
||||
class LegacyLocalCXXRuntimeOverrides : public LocalCXXRuntimeOverridesBase {
|
||||
public:
|
||||
/// Create a runtime-overrides class.
|
||||
template <typename MangleFtorT>
|
||||
LLVM_ATTRIBUTE_DEPRECATED(
|
||||
LegacyLocalCXXRuntimeOverrides(const MangleFtorT &Mangle),
|
||||
"ORCv1 utilities (utilities with the 'Legacy' prefix) are deprecated. "
|
||||
"Please use the ORCv2 LocalCXXRuntimeOverrides utility instead");
|
||||
|
||||
template <typename MangleFtorT>
|
||||
LegacyLocalCXXRuntimeOverrides(ORCv1DeprecationAcknowledgement,
|
||||
const MangleFtorT &Mangle) {
|
||||
addOverride(Mangle("__dso_handle"), toTargetAddress(&DSOHandleOverride));
|
||||
addOverride(Mangle("__cxa_atexit"), toTargetAddress(&CXAAtExitOverride));
|
||||
}
|
||||
|
||||
/// Search overrided symbols.
|
||||
JITEvaluatedSymbol searchOverrides(const std::string &Name) {
|
||||
auto I = CXXRuntimeOverrides.find(Name);
|
||||
if (I != CXXRuntimeOverrides.end())
|
||||
return JITEvaluatedSymbol(I->second, JITSymbolFlags::Exported);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
void addOverride(const std::string &Name, JITTargetAddress Addr) {
|
||||
CXXRuntimeOverrides.insert(std::make_pair(Name, Addr));
|
||||
}
|
||||
|
||||
StringMap<JITTargetAddress> CXXRuntimeOverrides;
|
||||
};
|
||||
|
||||
template <typename MangleFtorT>
|
||||
LegacyLocalCXXRuntimeOverrides::LegacyLocalCXXRuntimeOverrides(
|
||||
const MangleFtorT &Mangle) {
|
||||
addOverride(Mangle("__dso_handle"), toTargetAddress(&DSOHandleOverride));
|
||||
addOverride(Mangle("__cxa_atexit"), toTargetAddress(&CXAAtExitOverride));
|
||||
}
|
||||
|
||||
class LocalCXXRuntimeOverrides : public LocalCXXRuntimeOverridesBase {
|
||||
public:
|
||||
Error enable(JITDylib &JD, MangleAndInterner &Mangler);
|
||||
|
@ -1,110 +0,0 @@
|
||||
//===- GlobalMappingLayer.h - Run all IR through a functor ------*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Convenience layer for injecting symbols that will appear in calls to
|
||||
// findSymbol.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_EXECUTIONENGINE_ORC_GLOBALMAPPINGLAYER_H
|
||||
#define LLVM_EXECUTIONENGINE_ORC_GLOBALMAPPINGLAYER_H
|
||||
|
||||
#include "llvm/ExecutionEngine/JITSymbol.h"
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class Module;
|
||||
|
||||
namespace orc {
|
||||
|
||||
/// Global mapping layer.
|
||||
///
|
||||
/// This layer overrides the findSymbol method to first search a local symbol
|
||||
/// table that the client can define. It can be used to inject new symbol
|
||||
/// mappings into the JIT. Beware, however: symbols within a single IR module or
|
||||
/// object file will still resolve locally (via RuntimeDyld's symbol table) -
|
||||
/// such internal references cannot be overriden via this layer.
|
||||
template <typename BaseLayerT>
|
||||
class GlobalMappingLayer {
|
||||
public:
|
||||
|
||||
/// Handle to an added module.
|
||||
using ModuleHandleT = typename BaseLayerT::ModuleHandleT;
|
||||
|
||||
/// Construct an GlobalMappingLayer with the given BaseLayer
|
||||
GlobalMappingLayer(BaseLayerT &BaseLayer) : BaseLayer(BaseLayer) {}
|
||||
|
||||
/// Add the given module to the JIT.
|
||||
/// @return A handle for the added modules.
|
||||
Expected<ModuleHandleT>
|
||||
addModule(std::shared_ptr<Module> M,
|
||||
std::shared_ptr<JITSymbolResolver> Resolver) {
|
||||
return BaseLayer.addModule(std::move(M), std::move(Resolver));
|
||||
}
|
||||
|
||||
/// Remove the module set associated with the handle H.
|
||||
Error removeModule(ModuleHandleT H) { return BaseLayer.removeModule(H); }
|
||||
|
||||
/// Manually set the address to return for the given symbol.
|
||||
void setGlobalMapping(const std::string &Name, JITTargetAddress Addr) {
|
||||
SymbolTable[Name] = Addr;
|
||||
}
|
||||
|
||||
/// Remove the given symbol from the global mapping.
|
||||
void eraseGlobalMapping(const std::string &Name) {
|
||||
SymbolTable.erase(Name);
|
||||
}
|
||||
|
||||
/// Search for the given named symbol.
|
||||
///
|
||||
/// This method will first search the local symbol table, returning
|
||||
/// any symbol found there. If the symbol is not found in the local
|
||||
/// table then this call will be passed through to the base layer.
|
||||
///
|
||||
/// @param Name The name of the symbol to search for.
|
||||
/// @param ExportedSymbolsOnly If true, search only for exported symbols.
|
||||
/// @return A handle for the given named symbol, if it exists.
|
||||
JITSymbol findSymbol(const std::string &Name, bool ExportedSymbolsOnly) {
|
||||
auto I = SymbolTable.find(Name);
|
||||
if (I != SymbolTable.end())
|
||||
return JITSymbol(I->second, JITSymbolFlags::Exported);
|
||||
return BaseLayer.findSymbol(Name, ExportedSymbolsOnly);
|
||||
}
|
||||
|
||||
/// Get the address of the given symbol in the context of the of the
|
||||
/// module represented by the handle H. This call is forwarded to the
|
||||
/// base layer's implementation.
|
||||
/// @param H The handle for the module to search in.
|
||||
/// @param Name The name of the symbol to search for.
|
||||
/// @param ExportedSymbolsOnly If true, search only for exported symbols.
|
||||
/// @return A handle for the given named symbol, if it is found in the
|
||||
/// given module.
|
||||
JITSymbol findSymbolIn(ModuleHandleT H, const std::string &Name,
|
||||
bool ExportedSymbolsOnly) {
|
||||
return BaseLayer.findSymbolIn(H, Name, ExportedSymbolsOnly);
|
||||
}
|
||||
|
||||
/// Immediately emit and finalize the module set represented by the
|
||||
/// given handle.
|
||||
/// @param H Handle for module set to emit/finalize.
|
||||
Error emitAndFinalize(ModuleHandleT H) {
|
||||
return BaseLayer.emitAndFinalize(H);
|
||||
}
|
||||
|
||||
private:
|
||||
BaseLayerT &BaseLayer;
|
||||
std::map<std::string, JITTargetAddress> SymbolTable;
|
||||
};
|
||||
|
||||
} // end namespace orc
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_EXECUTIONENGINE_ORC_GLOBALMAPPINGLAYER_H
|
@ -66,99 +66,6 @@ private:
|
||||
NotifyCompiledFunction NotifyCompiled = NotifyCompiledFunction();
|
||||
};
|
||||
|
||||
/// Eager IR compiling layer.
|
||||
///
|
||||
/// This layer immediately compiles each IR module added via addModule to an
|
||||
/// object file and adds this module file to the layer below, which must
|
||||
/// implement the object layer concept.
|
||||
template <typename BaseLayerT, typename CompileFtor>
|
||||
class LegacyIRCompileLayer {
|
||||
public:
|
||||
/// Callback type for notifications when modules are compiled.
|
||||
using NotifyCompiledCallback =
|
||||
std::function<void(VModuleKey K, std::unique_ptr<Module>)>;
|
||||
|
||||
/// Construct an LegacyIRCompileLayer with the given BaseLayer, which must
|
||||
/// implement the ObjectLayer concept.
|
||||
LLVM_ATTRIBUTE_DEPRECATED(
|
||||
LegacyIRCompileLayer(
|
||||
BaseLayerT &BaseLayer, CompileFtor Compile,
|
||||
NotifyCompiledCallback NotifyCompiled = NotifyCompiledCallback()),
|
||||
"ORCv1 layers (layers with the 'Legacy' prefix) are deprecated. Please "
|
||||
"use "
|
||||
"the ORCv2 IRCompileLayer instead");
|
||||
|
||||
/// Legacy layer constructor with deprecation acknowledgement.
|
||||
LegacyIRCompileLayer(
|
||||
ORCv1DeprecationAcknowledgement, BaseLayerT &BaseLayer,
|
||||
CompileFtor Compile,
|
||||
NotifyCompiledCallback NotifyCompiled = NotifyCompiledCallback())
|
||||
: BaseLayer(BaseLayer), Compile(std::move(Compile)),
|
||||
NotifyCompiled(std::move(NotifyCompiled)) {}
|
||||
|
||||
/// Get a reference to the compiler functor.
|
||||
CompileFtor& getCompiler() { return Compile; }
|
||||
|
||||
/// (Re)set the NotifyCompiled callback.
|
||||
void setNotifyCompiled(NotifyCompiledCallback NotifyCompiled) {
|
||||
this->NotifyCompiled = std::move(NotifyCompiled);
|
||||
}
|
||||
|
||||
/// 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<Module> 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));
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
/// Remove the module associated with the VModuleKey K.
|
||||
Error removeModule(VModuleKey K) { return BaseLayer.removeObject(K); }
|
||||
|
||||
/// Search for the given named symbol.
|
||||
/// @param Name The name of the symbol to search for.
|
||||
/// @param ExportedSymbolsOnly If true, search only for exported symbols.
|
||||
/// @return A handle for the given named symbol, if it exists.
|
||||
JITSymbol findSymbol(const std::string &Name, bool ExportedSymbolsOnly) {
|
||||
return BaseLayer.findSymbol(Name, ExportedSymbolsOnly);
|
||||
}
|
||||
|
||||
/// Get the address of the given symbol in compiled module represented
|
||||
/// by the handle H. This call is forwarded to the base layer's
|
||||
/// implementation.
|
||||
/// @param K The VModuleKey for the module to search in.
|
||||
/// @param Name The name of the symbol to search for.
|
||||
/// @param ExportedSymbolsOnly If true, search only for exported symbols.
|
||||
/// @return A handle for the given named symbol, if it is found in the
|
||||
/// given module.
|
||||
JITSymbol findSymbolIn(VModuleKey K, const std::string &Name,
|
||||
bool ExportedSymbolsOnly) {
|
||||
return BaseLayer.findSymbolIn(K, Name, ExportedSymbolsOnly);
|
||||
}
|
||||
|
||||
/// Immediately emit and finalize the module represented by the given
|
||||
/// handle.
|
||||
/// @param K The VModuleKey for the module to emit/finalize.
|
||||
Error emitAndFinalize(VModuleKey K) { return BaseLayer.emitAndFinalize(K); }
|
||||
|
||||
private:
|
||||
BaseLayerT &BaseLayer;
|
||||
CompileFtor Compile;
|
||||
NotifyCompiledCallback NotifyCompiled;
|
||||
};
|
||||
|
||||
template <typename BaseLayerT, typename CompileFtor>
|
||||
LegacyIRCompileLayer<BaseLayerT, CompileFtor>::LegacyIRCompileLayer(
|
||||
BaseLayerT &BaseLayer, CompileFtor Compile,
|
||||
NotifyCompiledCallback NotifyCompiled)
|
||||
: BaseLayer(BaseLayer), Compile(std::move(Compile)),
|
||||
NotifyCompiled(std::move(NotifyCompiled)) {}
|
||||
|
||||
} // end namespace orc
|
||||
} // end namespace llvm
|
||||
|
||||
|
@ -51,80 +51,6 @@ private:
|
||||
TransformFunction Transform;
|
||||
};
|
||||
|
||||
/// IR mutating layer.
|
||||
///
|
||||
/// This layer applies a user supplied transform to each module that is added,
|
||||
/// then adds the transformed module to the layer below.
|
||||
template <typename BaseLayerT, typename TransformFtor>
|
||||
class LegacyIRTransformLayer {
|
||||
public:
|
||||
|
||||
/// Construct an LegacyIRTransformLayer with the given BaseLayer
|
||||
LLVM_ATTRIBUTE_DEPRECATED(
|
||||
LegacyIRTransformLayer(BaseLayerT &BaseLayer,
|
||||
TransformFtor Transform = TransformFtor()),
|
||||
"ORCv1 layers (layers with the 'Legacy' prefix) are deprecated. Please "
|
||||
"use "
|
||||
"the ORCv2 IRTransformLayer instead");
|
||||
|
||||
/// Legacy layer constructor with deprecation acknowledgement.
|
||||
LegacyIRTransformLayer(ORCv1DeprecationAcknowledgement, BaseLayerT &BaseLayer,
|
||||
TransformFtor Transform = TransformFtor())
|
||||
: BaseLayer(BaseLayer), Transform(std::move(Transform)) {}
|
||||
|
||||
/// Apply the transform functor to the module, then add the module to
|
||||
/// the layer below, along with the memory manager and symbol resolver.
|
||||
///
|
||||
/// @return A handle for the added modules.
|
||||
Error addModule(VModuleKey K, std::unique_ptr<Module> M) {
|
||||
return BaseLayer.addModule(std::move(K), Transform(std::move(M)));
|
||||
}
|
||||
|
||||
/// Remove the module associated with the VModuleKey K.
|
||||
Error removeModule(VModuleKey K) { return BaseLayer.removeModule(K); }
|
||||
|
||||
/// Search for the given named symbol.
|
||||
/// @param Name The name of the symbol to search for.
|
||||
/// @param ExportedSymbolsOnly If true, search only for exported symbols.
|
||||
/// @return A handle for the given named symbol, if it exists.
|
||||
JITSymbol findSymbol(const std::string &Name, bool ExportedSymbolsOnly) {
|
||||
return BaseLayer.findSymbol(Name, ExportedSymbolsOnly);
|
||||
}
|
||||
|
||||
/// Get the address of the given symbol in the context of the module
|
||||
/// represented by the VModuleKey K. This call is forwarded to the base
|
||||
/// layer's implementation.
|
||||
/// @param K The VModuleKey for the module to search in.
|
||||
/// @param Name The name of the symbol to search for.
|
||||
/// @param ExportedSymbolsOnly If true, search only for exported symbols.
|
||||
/// @return A handle for the given named symbol, if it is found in the
|
||||
/// given module.
|
||||
JITSymbol findSymbolIn(VModuleKey K, const std::string &Name,
|
||||
bool ExportedSymbolsOnly) {
|
||||
return BaseLayer.findSymbolIn(K, Name, ExportedSymbolsOnly);
|
||||
}
|
||||
|
||||
/// Immediately emit and finalize the module represented by the given
|
||||
/// VModuleKey.
|
||||
/// @param K The VModuleKey for the module to emit/finalize.
|
||||
Error emitAndFinalize(VModuleKey K) { return BaseLayer.emitAndFinalize(K); }
|
||||
|
||||
/// Access the transform functor directly.
|
||||
TransformFtor& getTransform() { return Transform; }
|
||||
|
||||
/// Access the mumate functor directly.
|
||||
const TransformFtor& getTransform() const { return Transform; }
|
||||
|
||||
private:
|
||||
BaseLayerT &BaseLayer;
|
||||
TransformFtor Transform;
|
||||
};
|
||||
|
||||
template <typename BaseLayerT, typename TransformFtor>
|
||||
LegacyIRTransformLayer<BaseLayerT, TransformFtor>::LegacyIRTransformLayer(
|
||||
BaseLayerT &BaseLayer, TransformFtor Transform)
|
||||
: BaseLayer(BaseLayer), Transform(std::move(Transform)) {}
|
||||
|
||||
} // end namespace orc
|
||||
} // end namespace llvm
|
||||
|
||||
|
@ -1,84 +0,0 @@
|
||||
//===- LambdaResolverMM - Redirect symbol lookup via a functor --*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Defines a RuntimeDyld::SymbolResolver subclass that uses a user-supplied
|
||||
// functor for symbol resolution.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_EXECUTIONENGINE_ORC_LAMBDARESOLVER_H
|
||||
#define LLVM_EXECUTIONENGINE_ORC_LAMBDARESOLVER_H
|
||||
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/ExecutionEngine/JITSymbol.h"
|
||||
#include "llvm/ExecutionEngine/OrcV1Deprecation.h"
|
||||
#include <memory>
|
||||
|
||||
namespace llvm {
|
||||
namespace orc {
|
||||
|
||||
template <typename DylibLookupFtorT, typename ExternalLookupFtorT>
|
||||
class LambdaResolver : public LegacyJITSymbolResolver {
|
||||
public:
|
||||
LLVM_ATTRIBUTE_DEPRECATED(
|
||||
LambdaResolver(DylibLookupFtorT DylibLookupFtor,
|
||||
ExternalLookupFtorT ExternalLookupFtor),
|
||||
"ORCv1 utilities (including resolvers) are deprecated and will be "
|
||||
"removed "
|
||||
"in the next release. Please use ORCv2 (see docs/ORCv2.rst)");
|
||||
|
||||
LambdaResolver(ORCv1DeprecationAcknowledgement,
|
||||
DylibLookupFtorT DylibLookupFtor,
|
||||
ExternalLookupFtorT ExternalLookupFtor)
|
||||
: DylibLookupFtor(DylibLookupFtor),
|
||||
ExternalLookupFtor(ExternalLookupFtor) {}
|
||||
|
||||
JITSymbol findSymbolInLogicalDylib(const std::string &Name) final {
|
||||
return DylibLookupFtor(Name);
|
||||
}
|
||||
|
||||
JITSymbol findSymbol(const std::string &Name) final {
|
||||
return ExternalLookupFtor(Name);
|
||||
}
|
||||
|
||||
private:
|
||||
DylibLookupFtorT DylibLookupFtor;
|
||||
ExternalLookupFtorT ExternalLookupFtor;
|
||||
};
|
||||
|
||||
template <typename DylibLookupFtorT, typename ExternalLookupFtorT>
|
||||
LambdaResolver<DylibLookupFtorT, ExternalLookupFtorT>::LambdaResolver(
|
||||
DylibLookupFtorT DylibLookupFtor, ExternalLookupFtorT ExternalLookupFtor)
|
||||
: DylibLookupFtor(DylibLookupFtor), ExternalLookupFtor(ExternalLookupFtor) {
|
||||
}
|
||||
|
||||
template <typename DylibLookupFtorT,
|
||||
typename ExternalLookupFtorT>
|
||||
std::shared_ptr<LambdaResolver<DylibLookupFtorT, ExternalLookupFtorT>>
|
||||
createLambdaResolver(DylibLookupFtorT DylibLookupFtor,
|
||||
ExternalLookupFtorT ExternalLookupFtor) {
|
||||
using LR = LambdaResolver<DylibLookupFtorT, ExternalLookupFtorT>;
|
||||
return std::make_unique<LR>(std::move(DylibLookupFtor),
|
||||
std::move(ExternalLookupFtor));
|
||||
}
|
||||
|
||||
template <typename DylibLookupFtorT, typename ExternalLookupFtorT>
|
||||
std::shared_ptr<LambdaResolver<DylibLookupFtorT, ExternalLookupFtorT>>
|
||||
createLambdaResolver(ORCv1DeprecationAcknowledgement,
|
||||
DylibLookupFtorT DylibLookupFtor,
|
||||
ExternalLookupFtorT ExternalLookupFtor) {
|
||||
using LR = LambdaResolver<DylibLookupFtorT, ExternalLookupFtorT>;
|
||||
return std::make_unique<LR>(AcknowledgeORCv1Deprecation,
|
||||
std::move(DylibLookupFtor),
|
||||
std::move(ExternalLookupFtor));
|
||||
}
|
||||
|
||||
} // end namespace orc
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_EXECUTIONENGINE_ORC_LAMBDARESOLVER_H
|
@ -1,267 +0,0 @@
|
||||
//===- LazyEmittingLayer.h - Lazily emit IR to lower JIT layers -*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Contains the definition for a lazy-emitting layer for the JIT.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_EXECUTIONENGINE_ORC_LAZYEMITTINGLAYER_H
|
||||
#define LLVM_EXECUTIONENGINE_ORC_LAZYEMITTINGLAYER_H
|
||||
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/ADT/StringMap.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/ExecutionEngine/JITSymbol.h"
|
||||
#include "llvm/ExecutionEngine/Orc/Core.h"
|
||||
#include "llvm/IR/GlobalValue.h"
|
||||
#include "llvm/IR/Mangler.h"
|
||||
#include "llvm/IR/Module.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <list>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
namespace llvm {
|
||||
namespace orc {
|
||||
|
||||
/// Lazy-emitting IR layer.
|
||||
///
|
||||
/// This layer accepts LLVM IR Modules (via addModule) but does not
|
||||
/// immediately emit them the layer below. Instead, emission to the base layer
|
||||
/// is deferred until the first time the client requests the address (via
|
||||
/// JITSymbol::getAddress) for a symbol contained in this layer.
|
||||
template <typename BaseLayerT> class LazyEmittingLayer {
|
||||
private:
|
||||
class EmissionDeferredModule {
|
||||
public:
|
||||
EmissionDeferredModule(VModuleKey K, std::unique_ptr<Module> M)
|
||||
: K(std::move(K)), M(std::move(M)) {}
|
||||
|
||||
JITSymbol find(StringRef Name, bool ExportedSymbolsOnly, BaseLayerT &B) {
|
||||
switch (EmitState) {
|
||||
case NotEmitted:
|
||||
if (auto GV = searchGVs(Name, ExportedSymbolsOnly)) {
|
||||
JITSymbolFlags Flags = JITSymbolFlags::fromGlobalValue(*GV);
|
||||
auto GetAddress = [this, ExportedSymbolsOnly, Name = Name.str(),
|
||||
&B]() -> Expected<JITTargetAddress> {
|
||||
if (this->EmitState == Emitting)
|
||||
return 0;
|
||||
else if (this->EmitState == NotEmitted) {
|
||||
this->EmitState = Emitting;
|
||||
if (auto Err = this->emitToBaseLayer(B))
|
||||
return std::move(Err);
|
||||
this->EmitState = Emitted;
|
||||
}
|
||||
if (auto Sym = B.findSymbolIn(K, Name, ExportedSymbolsOnly))
|
||||
return Sym.getAddress();
|
||||
else if (auto Err = Sym.takeError())
|
||||
return std::move(Err);
|
||||
else
|
||||
llvm_unreachable("Successful symbol lookup should return "
|
||||
"definition address here");
|
||||
};
|
||||
return JITSymbol(std::move(GetAddress), Flags);
|
||||
} else
|
||||
return nullptr;
|
||||
case Emitting:
|
||||
// Calling "emit" can trigger a recursive call to 'find' (e.g. to check
|
||||
// for pre-existing definitions of common-symbol), but any symbol in
|
||||
// this module would already have been found internally (in the
|
||||
// RuntimeDyld that did the lookup), so just return a nullptr here.
|
||||
return nullptr;
|
||||
case Emitted:
|
||||
return B.findSymbolIn(K, std::string(Name), ExportedSymbolsOnly);
|
||||
}
|
||||
llvm_unreachable("Invalid emit-state.");
|
||||
}
|
||||
|
||||
Error removeModuleFromBaseLayer(BaseLayerT& BaseLayer) {
|
||||
return EmitState != NotEmitted ? BaseLayer.removeModule(K)
|
||||
: Error::success();
|
||||
}
|
||||
|
||||
void emitAndFinalize(BaseLayerT &BaseLayer) {
|
||||
assert(EmitState != Emitting &&
|
||||
"Cannot emitAndFinalize while already emitting");
|
||||
if (EmitState == NotEmitted) {
|
||||
EmitState = Emitting;
|
||||
emitToBaseLayer(BaseLayer);
|
||||
EmitState = Emitted;
|
||||
}
|
||||
BaseLayer.emitAndFinalize(K);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
const GlobalValue* searchGVs(StringRef Name,
|
||||
bool ExportedSymbolsOnly) const {
|
||||
// FIXME: We could clean all this up if we had a way to reliably demangle
|
||||
// names: We could just demangle name and search, rather than
|
||||
// mangling everything else.
|
||||
|
||||
// If we have already built the mangled name set then just search it.
|
||||
if (MangledSymbols) {
|
||||
auto VI = MangledSymbols->find(Name);
|
||||
if (VI == MangledSymbols->end())
|
||||
return nullptr;
|
||||
auto GV = VI->second;
|
||||
if (!ExportedSymbolsOnly || GV->hasDefaultVisibility())
|
||||
return GV;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// If we haven't built the mangled name set yet, try to build it. As an
|
||||
// optimization this will leave MangledNames set to nullptr if we find
|
||||
// Name in the process of building the set.
|
||||
return buildMangledSymbols(Name, ExportedSymbolsOnly);
|
||||
}
|
||||
|
||||
Error emitToBaseLayer(BaseLayerT &BaseLayer) {
|
||||
// We don't need the mangled names set any more: Once we've emitted this
|
||||
// to the base layer we'll just look for symbols there.
|
||||
MangledSymbols.reset();
|
||||
return BaseLayer.addModule(std::move(K), std::move(M));
|
||||
}
|
||||
|
||||
// If the mangled name of the given GlobalValue matches the given search
|
||||
// name (and its visibility conforms to the ExportedSymbolsOnly flag) then
|
||||
// return the symbol. Otherwise, add the mangled name to the Names map and
|
||||
// return nullptr.
|
||||
const GlobalValue* addGlobalValue(StringMap<const GlobalValue*> &Names,
|
||||
const GlobalValue &GV,
|
||||
const Mangler &Mang, StringRef SearchName,
|
||||
bool ExportedSymbolsOnly) const {
|
||||
// Modules don't "provide" decls or common symbols.
|
||||
if (GV.isDeclaration() || GV.hasCommonLinkage())
|
||||
return nullptr;
|
||||
|
||||
// Mangle the GV name.
|
||||
std::string MangledName;
|
||||
{
|
||||
raw_string_ostream MangledNameStream(MangledName);
|
||||
Mang.getNameWithPrefix(MangledNameStream, &GV, false);
|
||||
}
|
||||
|
||||
// Check whether this is the name we were searching for, and if it is then
|
||||
// bail out early.
|
||||
if (MangledName == SearchName)
|
||||
if (!ExportedSymbolsOnly || GV.hasDefaultVisibility())
|
||||
return &GV;
|
||||
|
||||
// Otherwise add this to the map for later.
|
||||
Names[MangledName] = &GV;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Build the MangledSymbols map. Bails out early (with MangledSymbols left set
|
||||
// to nullptr) if the given SearchName is found while building the map.
|
||||
const GlobalValue* buildMangledSymbols(StringRef SearchName,
|
||||
bool ExportedSymbolsOnly) const {
|
||||
assert(!MangledSymbols && "Mangled symbols map already exists?");
|
||||
|
||||
auto Symbols = std::make_unique<StringMap<const GlobalValue*>>();
|
||||
|
||||
Mangler Mang;
|
||||
|
||||
for (const auto &GO : M->global_objects())
|
||||
if (auto GV = addGlobalValue(*Symbols, GO, Mang, SearchName,
|
||||
ExportedSymbolsOnly))
|
||||
return GV;
|
||||
|
||||
MangledSymbols = std::move(Symbols);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
enum { NotEmitted, Emitting, Emitted } EmitState = NotEmitted;
|
||||
VModuleKey K;
|
||||
std::unique_ptr<Module> M;
|
||||
mutable std::unique_ptr<StringMap<const GlobalValue*>> MangledSymbols;
|
||||
};
|
||||
|
||||
BaseLayerT &BaseLayer;
|
||||
std::map<VModuleKey, std::unique_ptr<EmissionDeferredModule>> ModuleMap;
|
||||
|
||||
public:
|
||||
|
||||
/// Construct a lazy emitting layer.
|
||||
LLVM_ATTRIBUTE_DEPRECATED(
|
||||
LazyEmittingLayer(BaseLayerT &BaseLayer),
|
||||
"ORCv1 layers (including LazyEmittingLayer) are deprecated. Please use "
|
||||
"ORCv2, where lazy emission is the default");
|
||||
|
||||
/// Construct a lazy emitting layer.
|
||||
LazyEmittingLayer(ORCv1DeprecationAcknowledgement, BaseLayerT &BaseLayer)
|
||||
: BaseLayer(BaseLayer) {}
|
||||
|
||||
/// Add the given module to the lazy emitting layer.
|
||||
Error addModule(VModuleKey K, std::unique_ptr<Module> M) {
|
||||
assert(!ModuleMap.count(K) && "VModuleKey K already in use");
|
||||
ModuleMap[K] =
|
||||
std::make_unique<EmissionDeferredModule>(std::move(K), std::move(M));
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
/// Remove the module represented by the given handle.
|
||||
///
|
||||
/// This method will free the memory associated with the given module, both
|
||||
/// in this layer, and the base layer.
|
||||
Error removeModule(VModuleKey K) {
|
||||
auto I = ModuleMap.find(K);
|
||||
assert(I != ModuleMap.end() && "VModuleKey K not valid here");
|
||||
auto EDM = std::move(I.second);
|
||||
ModuleMap.erase(I);
|
||||
return EDM->removeModuleFromBaseLayer(BaseLayer);
|
||||
}
|
||||
|
||||
/// Search for the given named symbol.
|
||||
/// @param Name The name of the symbol to search for.
|
||||
/// @param ExportedSymbolsOnly If true, search only for exported symbols.
|
||||
/// @return A handle for the given named symbol, if it exists.
|
||||
JITSymbol findSymbol(const std::string &Name, bool ExportedSymbolsOnly) {
|
||||
// Look for the symbol among existing definitions.
|
||||
if (auto Symbol = BaseLayer.findSymbol(Name, ExportedSymbolsOnly))
|
||||
return Symbol;
|
||||
|
||||
// If not found then search the deferred modules. If any of these contain a
|
||||
// definition of 'Name' then they will return a JITSymbol that will emit
|
||||
// the corresponding module when the symbol address is requested.
|
||||
for (auto &KV : ModuleMap)
|
||||
if (auto Symbol = KV.second->find(Name, ExportedSymbolsOnly, BaseLayer))
|
||||
return Symbol;
|
||||
|
||||
// If no definition found anywhere return a null symbol.
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/// Get the address of the given symbol in the context of the of
|
||||
/// compiled modules represented by the key K.
|
||||
JITSymbol findSymbolIn(VModuleKey K, const std::string &Name,
|
||||
bool ExportedSymbolsOnly) {
|
||||
assert(ModuleMap.count(K) && "VModuleKey K not valid here");
|
||||
return ModuleMap[K]->find(Name, ExportedSymbolsOnly, BaseLayer);
|
||||
}
|
||||
|
||||
/// Immediately emit and finalize the module represented by the given
|
||||
/// key.
|
||||
Error emitAndFinalize(VModuleKey K) {
|
||||
assert(ModuleMap.count(K) && "VModuleKey K not valid here");
|
||||
return ModuleMap[K]->emitAndFinalize(BaseLayer);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename BaseLayerT>
|
||||
LazyEmittingLayer<BaseLayerT>::LazyEmittingLayer(BaseLayerT &BaseLayer)
|
||||
: BaseLayer(BaseLayer) {}
|
||||
|
||||
} // end namespace orc
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_EXECUTIONENGINE_ORC_LAZYEMITTINGLAYER_H
|
@ -1,211 +0,0 @@
|
||||
//===--- Legacy.h -- Adapters for ExecutionEngine API interop ---*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Contains core ORC APIs.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_EXECUTIONENGINE_ORC_LEGACY_H
|
||||
#define LLVM_EXECUTIONENGINE_ORC_LEGACY_H
|
||||
|
||||
#include "llvm/ExecutionEngine/JITSymbol.h"
|
||||
#include "llvm/ExecutionEngine/Orc/Core.h"
|
||||
|
||||
namespace llvm {
|
||||
namespace orc {
|
||||
|
||||
/// SymbolResolver is a composable interface for looking up symbol flags
|
||||
/// and addresses using the AsynchronousSymbolQuery type. It will
|
||||
/// eventually replace the LegacyJITSymbolResolver interface as the
|
||||
/// stardard ORC symbol resolver type.
|
||||
///
|
||||
/// FIXME: SymbolResolvers should go away and be replaced with VSOs with
|
||||
/// defenition generators.
|
||||
class SymbolResolver {
|
||||
public:
|
||||
virtual ~SymbolResolver() = default;
|
||||
|
||||
/// Returns the subset of the given symbols that the caller is responsible for
|
||||
/// materializing.
|
||||
virtual SymbolNameSet getResponsibilitySet(const SymbolNameSet &Symbols) = 0;
|
||||
|
||||
/// For each symbol in Symbols that can be found, assigns that symbols
|
||||
/// value in Query. Returns the set of symbols that could not be found.
|
||||
virtual SymbolNameSet lookup(std::shared_ptr<AsynchronousSymbolQuery> Query,
|
||||
SymbolNameSet Symbols) = 0;
|
||||
|
||||
private:
|
||||
virtual void anchor();
|
||||
};
|
||||
|
||||
/// Implements SymbolResolver with a pair of supplied function objects
|
||||
/// for convenience. See createSymbolResolver.
|
||||
template <typename GetResponsibilitySetFn, typename LookupFn>
|
||||
class LambdaSymbolResolver final : public SymbolResolver {
|
||||
public:
|
||||
template <typename GetResponsibilitySetFnRef, typename LookupFnRef>
|
||||
LambdaSymbolResolver(GetResponsibilitySetFnRef &&GetResponsibilitySet,
|
||||
LookupFnRef &&Lookup)
|
||||
: GetResponsibilitySet(
|
||||
std::forward<GetResponsibilitySetFnRef>(GetResponsibilitySet)),
|
||||
Lookup(std::forward<LookupFnRef>(Lookup)) {}
|
||||
|
||||
SymbolNameSet getResponsibilitySet(const SymbolNameSet &Symbols) final {
|
||||
return GetResponsibilitySet(Symbols);
|
||||
}
|
||||
|
||||
SymbolNameSet lookup(std::shared_ptr<AsynchronousSymbolQuery> Query,
|
||||
SymbolNameSet Symbols) final {
|
||||
return Lookup(std::move(Query), std::move(Symbols));
|
||||
}
|
||||
|
||||
private:
|
||||
GetResponsibilitySetFn GetResponsibilitySet;
|
||||
LookupFn Lookup;
|
||||
};
|
||||
|
||||
/// Creates a SymbolResolver implementation from the pair of supplied
|
||||
/// function objects.
|
||||
template <typename GetResponsibilitySetFn, typename LookupFn>
|
||||
std::unique_ptr<LambdaSymbolResolver<
|
||||
std::remove_cv_t<std::remove_reference_t<GetResponsibilitySetFn>>,
|
||||
std::remove_cv_t<std::remove_reference_t<LookupFn>>>>
|
||||
createSymbolResolver(GetResponsibilitySetFn &&GetResponsibilitySet,
|
||||
LookupFn &&Lookup) {
|
||||
using LambdaSymbolResolverImpl = LambdaSymbolResolver<
|
||||
std::remove_cv_t<std::remove_reference_t<GetResponsibilitySetFn>>,
|
||||
std::remove_cv_t<std::remove_reference_t<LookupFn>>>;
|
||||
return std::make_unique<LambdaSymbolResolverImpl>(
|
||||
std::forward<GetResponsibilitySetFn>(GetResponsibilitySet),
|
||||
std::forward<LookupFn>(Lookup));
|
||||
}
|
||||
|
||||
/// Legacy adapter. Remove once we kill off the old ORC layers.
|
||||
class JITSymbolResolverAdapter : public JITSymbolResolver {
|
||||
public:
|
||||
JITSymbolResolverAdapter(ExecutionSession &ES, SymbolResolver &R,
|
||||
MaterializationResponsibility *MR);
|
||||
Expected<LookupSet> getResponsibilitySet(const LookupSet &Symbols) override;
|
||||
void lookup(const LookupSet &Symbols, OnResolvedFunction OnResolved) override;
|
||||
|
||||
private:
|
||||
ExecutionSession &ES;
|
||||
std::set<SymbolStringPtr> ResolvedStrings;
|
||||
SymbolResolver &R;
|
||||
MaterializationResponsibility *MR;
|
||||
};
|
||||
|
||||
/// Use the given legacy-style FindSymbol function (i.e. a function that takes
|
||||
/// a const std::string& or StringRef and returns a JITSymbol) to get the
|
||||
/// subset of symbols that the caller is responsible for materializing. If any
|
||||
/// JITSymbol returned by FindSymbol is in an error state the function returns
|
||||
/// immediately with that error.
|
||||
///
|
||||
/// Useful for implementing getResponsibilitySet bodies that query legacy
|
||||
/// resolvers.
|
||||
template <typename FindSymbolFn>
|
||||
Expected<SymbolNameSet>
|
||||
getResponsibilitySetWithLegacyFn(const SymbolNameSet &Symbols,
|
||||
FindSymbolFn FindSymbol) {
|
||||
SymbolNameSet Result;
|
||||
|
||||
for (auto &S : Symbols) {
|
||||
if (JITSymbol Sym = FindSymbol(*S)) {
|
||||
if (!Sym.getFlags().isStrong())
|
||||
Result.insert(S);
|
||||
} else if (auto Err = Sym.takeError())
|
||||
return std::move(Err);
|
||||
}
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
/// Use the given legacy-style FindSymbol function (i.e. a function that
|
||||
/// takes a const std::string& or StringRef and returns a JITSymbol) to
|
||||
/// find the address and flags for each symbol in Symbols and store the
|
||||
/// result in Query. If any JITSymbol returned by FindSymbol is in an
|
||||
/// error then Query.notifyFailed(...) is called with that error and the
|
||||
/// function returns immediately. On success, returns the set of symbols
|
||||
/// not found.
|
||||
///
|
||||
/// Useful for implementing lookup bodies that query legacy resolvers.
|
||||
template <typename FindSymbolFn>
|
||||
SymbolNameSet
|
||||
lookupWithLegacyFn(ExecutionSession &ES, AsynchronousSymbolQuery &Query,
|
||||
const SymbolNameSet &Symbols, FindSymbolFn FindSymbol) {
|
||||
SymbolNameSet SymbolsNotFound;
|
||||
bool NewSymbolsResolved = false;
|
||||
|
||||
for (auto &S : Symbols) {
|
||||
if (JITSymbol Sym = FindSymbol(*S)) {
|
||||
if (auto Addr = Sym.getAddress()) {
|
||||
Query.notifySymbolMetRequiredState(
|
||||
S, JITEvaluatedSymbol(*Addr, Sym.getFlags()));
|
||||
NewSymbolsResolved = true;
|
||||
} else {
|
||||
ES.legacyFailQuery(Query, Addr.takeError());
|
||||
return SymbolNameSet();
|
||||
}
|
||||
} else if (auto Err = Sym.takeError()) {
|
||||
ES.legacyFailQuery(Query, std::move(Err));
|
||||
return SymbolNameSet();
|
||||
} else
|
||||
SymbolsNotFound.insert(S);
|
||||
}
|
||||
|
||||
if (NewSymbolsResolved && Query.isComplete())
|
||||
Query.handleComplete();
|
||||
|
||||
return SymbolsNotFound;
|
||||
}
|
||||
|
||||
/// An ORC SymbolResolver implementation that uses a legacy
|
||||
/// findSymbol-like function to perform lookup;
|
||||
template <typename LegacyLookupFn>
|
||||
class LegacyLookupFnResolver final : public SymbolResolver {
|
||||
public:
|
||||
using ErrorReporter = std::function<void(Error)>;
|
||||
|
||||
LegacyLookupFnResolver(ExecutionSession &ES, LegacyLookupFn LegacyLookup,
|
||||
ErrorReporter ReportError)
|
||||
: ES(ES), LegacyLookup(std::move(LegacyLookup)),
|
||||
ReportError(std::move(ReportError)) {}
|
||||
|
||||
SymbolNameSet getResponsibilitySet(const SymbolNameSet &Symbols) final {
|
||||
if (auto ResponsibilitySet =
|
||||
getResponsibilitySetWithLegacyFn(Symbols, LegacyLookup))
|
||||
return std::move(*ResponsibilitySet);
|
||||
else {
|
||||
ReportError(ResponsibilitySet.takeError());
|
||||
return SymbolNameSet();
|
||||
}
|
||||
}
|
||||
|
||||
SymbolNameSet lookup(std::shared_ptr<AsynchronousSymbolQuery> Query,
|
||||
SymbolNameSet Symbols) final {
|
||||
return lookupWithLegacyFn(ES, *Query, Symbols, LegacyLookup);
|
||||
}
|
||||
|
||||
private:
|
||||
ExecutionSession &ES;
|
||||
LegacyLookupFn LegacyLookup;
|
||||
ErrorReporter ReportError;
|
||||
};
|
||||
|
||||
template <typename LegacyLookupFn>
|
||||
std::shared_ptr<LegacyLookupFnResolver<LegacyLookupFn>>
|
||||
createLegacyLookupResolver(ExecutionSession &ES, LegacyLookupFn LegacyLookup,
|
||||
std::function<void(Error)> ErrorReporter) {
|
||||
return std::make_shared<LegacyLookupFnResolver<LegacyLookupFn>>(
|
||||
ES, std::move(LegacyLookup), std::move(ErrorReporter));
|
||||
}
|
||||
|
||||
} // End namespace orc
|
||||
} // End namespace llvm
|
||||
|
||||
#endif // LLVM_EXECUTIONENGINE_ORC_LEGACY_H
|
@ -1,43 +0,0 @@
|
||||
//===------ NullResolver.h - Reject symbol lookup requests ------*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Defines a RuntimeDyld::SymbolResolver subclass that rejects all symbol
|
||||
// resolution requests, for clients that have no cross-object fixups.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_EXECUTIONENGINE_ORC_NULLRESOLVER_H
|
||||
#define LLVM_EXECUTIONENGINE_ORC_NULLRESOLVER_H
|
||||
|
||||
#include "llvm/ExecutionEngine/Orc/Legacy.h"
|
||||
#include "llvm/ExecutionEngine/RuntimeDyld.h"
|
||||
|
||||
namespace llvm {
|
||||
namespace orc {
|
||||
|
||||
class NullResolver : public SymbolResolver {
|
||||
public:
|
||||
SymbolNameSet getResponsibilitySet(const SymbolNameSet &Symbols) final;
|
||||
|
||||
SymbolNameSet lookup(std::shared_ptr<AsynchronousSymbolQuery> Query,
|
||||
SymbolNameSet Symbols) final;
|
||||
};
|
||||
|
||||
/// SymbolResolver impliementation that rejects all resolution requests.
|
||||
/// Useful for clients that have no cross-object fixups.
|
||||
class NullLegacyResolver : public LegacyJITSymbolResolver {
|
||||
public:
|
||||
JITSymbol findSymbol(const std::string &Name) final;
|
||||
|
||||
JITSymbol findSymbolInLogicalDylib(const std::string &Name) final;
|
||||
};
|
||||
|
||||
} // End namespace orc.
|
||||
} // End namespace llvm.
|
||||
|
||||
#endif // LLVM_EXECUTIONENGINE_ORC_NULLRESOLVER_H
|
@ -43,88 +43,6 @@ private:
|
||||
TransformFunction Transform;
|
||||
};
|
||||
|
||||
/// Object mutating layer.
|
||||
///
|
||||
/// This layer accepts sets of ObjectFiles (via addObject). It
|
||||
/// immediately applies the user supplied functor to each object, then adds
|
||||
/// the set of transformed objects to the layer below.
|
||||
template <typename BaseLayerT, typename TransformFtor>
|
||||
class LegacyObjectTransformLayer {
|
||||
public:
|
||||
/// Construct an ObjectTransformLayer with the given BaseLayer
|
||||
LLVM_ATTRIBUTE_DEPRECATED(
|
||||
LegacyObjectTransformLayer(BaseLayerT &BaseLayer,
|
||||
TransformFtor Transform = TransformFtor()),
|
||||
"ORCv1 layers (layers with the 'Legacy' prefix) are deprecated. Please "
|
||||
"use "
|
||||
"the ORCv2 ObjectTransformLayer instead");
|
||||
|
||||
/// Legacy layer constructor with deprecation acknowledgement.
|
||||
LegacyObjectTransformLayer(ORCv1DeprecationAcknowledgement,
|
||||
BaseLayerT &BaseLayer,
|
||||
TransformFtor Transform = TransformFtor())
|
||||
: BaseLayer(BaseLayer), Transform(std::move(Transform)) {}
|
||||
|
||||
/// Apply the transform functor to each object in the object set, then
|
||||
/// add the resulting set of objects to the base layer, along with the
|
||||
/// memory manager and symbol resolver.
|
||||
///
|
||||
/// @return A handle for the added objects.
|
||||
template <typename ObjectPtr> Error addObject(VModuleKey K, ObjectPtr Obj) {
|
||||
return BaseLayer.addObject(std::move(K), Transform(std::move(Obj)));
|
||||
}
|
||||
|
||||
/// Remove the object set associated with the VModuleKey K.
|
||||
Error removeObject(VModuleKey K) { return BaseLayer.removeObject(K); }
|
||||
|
||||
/// Search for the given named symbol.
|
||||
/// @param Name The name of the symbol to search for.
|
||||
/// @param ExportedSymbolsOnly If true, search only for exported symbols.
|
||||
/// @return A handle for the given named symbol, if it exists.
|
||||
JITSymbol findSymbol(const std::string &Name, bool ExportedSymbolsOnly) {
|
||||
return BaseLayer.findSymbol(Name, ExportedSymbolsOnly);
|
||||
}
|
||||
|
||||
/// Get the address of the given symbol in the context of the set of
|
||||
/// objects represented by the VModuleKey K. This call is forwarded to
|
||||
/// the base layer's implementation.
|
||||
/// @param K The VModuleKey associated with the object set to search in.
|
||||
/// @param Name The name of the symbol to search for.
|
||||
/// @param ExportedSymbolsOnly If true, search only for exported symbols.
|
||||
/// @return A handle for the given named symbol, if it is found in the
|
||||
/// given object set.
|
||||
JITSymbol findSymbolIn(VModuleKey K, const std::string &Name,
|
||||
bool ExportedSymbolsOnly) {
|
||||
return BaseLayer.findSymbolIn(K, Name, ExportedSymbolsOnly);
|
||||
}
|
||||
|
||||
/// Immediately emit and finalize the object set represented by the
|
||||
/// given VModuleKey K.
|
||||
Error emitAndFinalize(VModuleKey K) { return BaseLayer.emitAndFinalize(K); }
|
||||
|
||||
/// Map section addresses for the objects associated with the
|
||||
/// VModuleKey K.
|
||||
void mapSectionAddress(VModuleKey K, const void *LocalAddress,
|
||||
JITTargetAddress TargetAddr) {
|
||||
BaseLayer.mapSectionAddress(K, LocalAddress, TargetAddr);
|
||||
}
|
||||
|
||||
/// Access the transform functor directly.
|
||||
TransformFtor &getTransform() { return Transform; }
|
||||
|
||||
/// Access the mumate functor directly.
|
||||
const TransformFtor &getTransform() const { return Transform; }
|
||||
|
||||
private:
|
||||
BaseLayerT &BaseLayer;
|
||||
TransformFtor Transform;
|
||||
};
|
||||
|
||||
template <typename BaseLayerT, typename TransformFtor>
|
||||
LegacyObjectTransformLayer<BaseLayerT, TransformFtor>::
|
||||
LegacyObjectTransformLayer(BaseLayerT &BaseLayer, TransformFtor Transform)
|
||||
: BaseLayer(BaseLayer), Transform(std::move(Transform)) {}
|
||||
|
||||
} // end namespace orc
|
||||
} // end namespace llvm
|
||||
|
||||
|
@ -20,7 +20,6 @@
|
||||
#include "llvm/ExecutionEngine/JITSymbol.h"
|
||||
#include "llvm/ExecutionEngine/Orc/Core.h"
|
||||
#include "llvm/ExecutionEngine/Orc/Layer.h"
|
||||
#include "llvm/ExecutionEngine/Orc/Legacy.h"
|
||||
#include "llvm/ExecutionEngine/RuntimeDyld.h"
|
||||
#include "llvm/Object/ObjectFile.h"
|
||||
#include "llvm/Support/Error.h"
|
||||
@ -148,356 +147,6 @@ private:
|
||||
LoadedObjInfos;
|
||||
};
|
||||
|
||||
class LegacyRTDyldObjectLinkingLayerBase {
|
||||
public:
|
||||
using ObjectPtr = std::unique_ptr<MemoryBuffer>;
|
||||
|
||||
protected:
|
||||
|
||||
/// Holds an object to be allocated/linked as a unit in the JIT.
|
||||
///
|
||||
/// An instance of this class will be created for each object added
|
||||
/// via JITObjectLayer::addObject. Deleting the instance (via
|
||||
/// removeObject) frees its memory, removing all symbol definitions that
|
||||
/// had been provided by this instance. Higher level layers are responsible
|
||||
/// for taking any action required to handle the missing symbols.
|
||||
class LinkedObject {
|
||||
public:
|
||||
LinkedObject() = default;
|
||||
LinkedObject(const LinkedObject&) = delete;
|
||||
void operator=(const LinkedObject&) = delete;
|
||||
virtual ~LinkedObject() = default;
|
||||
|
||||
virtual Error finalize() = 0;
|
||||
|
||||
virtual JITSymbol::GetAddressFtor
|
||||
getSymbolMaterializer(std::string Name) = 0;
|
||||
|
||||
virtual void mapSectionAddress(const void *LocalAddress,
|
||||
JITTargetAddress TargetAddr) const = 0;
|
||||
|
||||
JITSymbol getSymbol(StringRef Name, bool ExportedSymbolsOnly) {
|
||||
auto SymEntry = SymbolTable.find(Name);
|
||||
if (SymEntry == SymbolTable.end())
|
||||
return nullptr;
|
||||
if (!SymEntry->second.getFlags().isExported() && ExportedSymbolsOnly)
|
||||
return nullptr;
|
||||
if (!Finalized)
|
||||
return JITSymbol(getSymbolMaterializer(std::string(Name)),
|
||||
SymEntry->second.getFlags());
|
||||
return JITSymbol(SymEntry->second);
|
||||
}
|
||||
|
||||
protected:
|
||||
StringMap<JITEvaluatedSymbol> SymbolTable;
|
||||
bool Finalized = false;
|
||||
};
|
||||
};
|
||||
|
||||
/// Bare bones object linking layer.
|
||||
///
|
||||
/// This class is intended to be used as the base layer for a JIT. It allows
|
||||
/// object files to be loaded into memory, linked, and the addresses of their
|
||||
/// symbols queried. All objects added to this layer can see each other's
|
||||
/// symbols.
|
||||
class LegacyRTDyldObjectLinkingLayer : public LegacyRTDyldObjectLinkingLayerBase {
|
||||
public:
|
||||
|
||||
using LegacyRTDyldObjectLinkingLayerBase::ObjectPtr;
|
||||
|
||||
/// Functor for receiving object-loaded notifications.
|
||||
using NotifyLoadedFtor =
|
||||
std::function<void(VModuleKey, const object::ObjectFile &Obj,
|
||||
const RuntimeDyld::LoadedObjectInfo &)>;
|
||||
|
||||
/// Functor for receiving finalization notifications.
|
||||
using NotifyFinalizedFtor =
|
||||
std::function<void(VModuleKey, const object::ObjectFile &Obj,
|
||||
const RuntimeDyld::LoadedObjectInfo &)>;
|
||||
|
||||
/// Functor for receiving deallocation notifications.
|
||||
using NotifyFreedFtor = std::function<void(VModuleKey, const object::ObjectFile &Obj)>;
|
||||
|
||||
private:
|
||||
using OwnedObject = object::OwningBinary<object::ObjectFile>;
|
||||
|
||||
template <typename MemoryManagerPtrT>
|
||||
class ConcreteLinkedObject : public LinkedObject {
|
||||
public:
|
||||
ConcreteLinkedObject(LegacyRTDyldObjectLinkingLayer &Parent, VModuleKey K,
|
||||
OwnedObject Obj, MemoryManagerPtrT MemMgr,
|
||||
std::shared_ptr<SymbolResolver> Resolver,
|
||||
bool ProcessAllSections)
|
||||
: K(std::move(K)),
|
||||
Parent(Parent),
|
||||
MemMgr(std::move(MemMgr)),
|
||||
PFC(std::make_unique<PreFinalizeContents>(
|
||||
std::move(Obj), std::move(Resolver),
|
||||
ProcessAllSections)) {
|
||||
buildInitialSymbolTable(PFC->Obj);
|
||||
}
|
||||
|
||||
~ConcreteLinkedObject() override {
|
||||
if (this->Parent.NotifyFreed && ObjForNotify.getBinary())
|
||||
this->Parent.NotifyFreed(K, *ObjForNotify.getBinary());
|
||||
|
||||
MemMgr->deregisterEHFrames();
|
||||
}
|
||||
|
||||
Error finalize() override {
|
||||
assert(PFC && "mapSectionAddress called on finalized LinkedObject");
|
||||
|
||||
JITSymbolResolverAdapter ResolverAdapter(Parent.ES, *PFC->Resolver,
|
||||
nullptr);
|
||||
PFC->RTDyld = std::make_unique<RuntimeDyld>(*MemMgr, ResolverAdapter);
|
||||
PFC->RTDyld->setProcessAllSections(PFC->ProcessAllSections);
|
||||
|
||||
Finalized = true;
|
||||
|
||||
std::unique_ptr<RuntimeDyld::LoadedObjectInfo> Info =
|
||||
PFC->RTDyld->loadObject(*PFC->Obj.getBinary());
|
||||
|
||||
// Copy the symbol table out of the RuntimeDyld instance.
|
||||
{
|
||||
auto SymTab = PFC->RTDyld->getSymbolTable();
|
||||
for (auto &KV : SymTab)
|
||||
SymbolTable[KV.first] = KV.second;
|
||||
}
|
||||
|
||||
if (Parent.NotifyLoaded)
|
||||
Parent.NotifyLoaded(K, *PFC->Obj.getBinary(), *Info);
|
||||
|
||||
PFC->RTDyld->finalizeWithMemoryManagerLocking();
|
||||
|
||||
if (PFC->RTDyld->hasError())
|
||||
return make_error<StringError>(PFC->RTDyld->getErrorString(),
|
||||
inconvertibleErrorCode());
|
||||
|
||||
if (Parent.NotifyFinalized)
|
||||
Parent.NotifyFinalized(K, *PFC->Obj.getBinary(), *Info);
|
||||
|
||||
// Release resources.
|
||||
if (this->Parent.NotifyFreed)
|
||||
ObjForNotify = std::move(PFC->Obj); // needed for callback
|
||||
PFC = nullptr;
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
JITSymbol::GetAddressFtor getSymbolMaterializer(std::string Name) override {
|
||||
return [this, Name]() -> Expected<JITTargetAddress> {
|
||||
// The symbol may be materialized between the creation of this lambda
|
||||
// and its execution, so we need to double check.
|
||||
if (!this->Finalized)
|
||||
if (auto Err = this->finalize())
|
||||
return std::move(Err);
|
||||
return this->getSymbol(Name, false).getAddress();
|
||||
};
|
||||
}
|
||||
|
||||
void mapSectionAddress(const void *LocalAddress,
|
||||
JITTargetAddress TargetAddr) const override {
|
||||
assert(PFC && "mapSectionAddress called on finalized LinkedObject");
|
||||
assert(PFC->RTDyld && "mapSectionAddress called on raw LinkedObject");
|
||||
PFC->RTDyld->mapSectionAddress(LocalAddress, TargetAddr);
|
||||
}
|
||||
|
||||
private:
|
||||
void buildInitialSymbolTable(const OwnedObject &Obj) {
|
||||
for (auto &Symbol : Obj.getBinary()->symbols()) {
|
||||
if (Expected<uint32_t> SymbolFlagsOrErr = Symbol.getFlags()) {
|
||||
if (*SymbolFlagsOrErr & object::SymbolRef::SF_Undefined)
|
||||
continue;
|
||||
} else {
|
||||
// FIXME: Raise an error for bad symbols.
|
||||
consumeError(SymbolFlagsOrErr.takeError());
|
||||
continue;
|
||||
}
|
||||
|
||||
Expected<StringRef> SymbolName = Symbol.getName();
|
||||
// FIXME: Raise an error for bad symbols.
|
||||
if (!SymbolName) {
|
||||
consumeError(SymbolName.takeError());
|
||||
continue;
|
||||
}
|
||||
// FIXME: Raise an error for bad symbols.
|
||||
auto Flags = JITSymbolFlags::fromObjectSymbol(Symbol);
|
||||
if (!Flags) {
|
||||
consumeError(Flags.takeError());
|
||||
continue;
|
||||
}
|
||||
SymbolTable.insert(
|
||||
std::make_pair(*SymbolName, JITEvaluatedSymbol(0, *Flags)));
|
||||
}
|
||||
}
|
||||
|
||||
// Contains the information needed prior to finalization: the object files,
|
||||
// memory manager, resolver, and flags needed for RuntimeDyld.
|
||||
struct PreFinalizeContents {
|
||||
PreFinalizeContents(OwnedObject Obj,
|
||||
std::shared_ptr<SymbolResolver> Resolver,
|
||||
bool ProcessAllSections)
|
||||
: Obj(std::move(Obj)),
|
||||
Resolver(std::move(Resolver)),
|
||||
ProcessAllSections(ProcessAllSections) {}
|
||||
|
||||
OwnedObject Obj;
|
||||
std::shared_ptr<SymbolResolver> Resolver;
|
||||
bool ProcessAllSections;
|
||||
std::unique_ptr<RuntimeDyld> RTDyld;
|
||||
};
|
||||
|
||||
VModuleKey K;
|
||||
LegacyRTDyldObjectLinkingLayer &Parent;
|
||||
MemoryManagerPtrT MemMgr;
|
||||
OwnedObject ObjForNotify;
|
||||
std::unique_ptr<PreFinalizeContents> PFC;
|
||||
};
|
||||
|
||||
template <typename MemoryManagerPtrT>
|
||||
std::unique_ptr<ConcreteLinkedObject<MemoryManagerPtrT>>
|
||||
createLinkedObject(LegacyRTDyldObjectLinkingLayer &Parent, VModuleKey K,
|
||||
OwnedObject Obj, MemoryManagerPtrT MemMgr,
|
||||
std::shared_ptr<SymbolResolver> Resolver,
|
||||
bool ProcessAllSections) {
|
||||
using LOS = ConcreteLinkedObject<MemoryManagerPtrT>;
|
||||
return std::make_unique<LOS>(Parent, std::move(K), std::move(Obj),
|
||||
std::move(MemMgr), std::move(Resolver),
|
||||
ProcessAllSections);
|
||||
}
|
||||
|
||||
public:
|
||||
struct Resources {
|
||||
std::shared_ptr<RuntimeDyld::MemoryManager> MemMgr;
|
||||
std::shared_ptr<SymbolResolver> Resolver;
|
||||
};
|
||||
|
||||
using ResourcesGetter = std::function<Resources(VModuleKey)>;
|
||||
|
||||
/// Construct an ObjectLinkingLayer with the given NotifyLoaded,
|
||||
/// and NotifyFinalized functors.
|
||||
LLVM_ATTRIBUTE_DEPRECATED(
|
||||
LegacyRTDyldObjectLinkingLayer(
|
||||
ExecutionSession &ES, ResourcesGetter GetResources,
|
||||
NotifyLoadedFtor NotifyLoaded = NotifyLoadedFtor(),
|
||||
NotifyFinalizedFtor NotifyFinalized = NotifyFinalizedFtor(),
|
||||
NotifyFreedFtor NotifyFreed = NotifyFreedFtor()),
|
||||
"ORCv1 layers (layers with the 'Legacy' prefix) are deprecated. Please "
|
||||
"use "
|
||||
"ORCv2 (see docs/ORCv2.rst)");
|
||||
|
||||
// Legacy layer constructor with deprecation acknowledgement.
|
||||
LegacyRTDyldObjectLinkingLayer(
|
||||
ORCv1DeprecationAcknowledgement, ExecutionSession &ES,
|
||||
ResourcesGetter GetResources,
|
||||
NotifyLoadedFtor NotifyLoaded = NotifyLoadedFtor(),
|
||||
NotifyFinalizedFtor NotifyFinalized = NotifyFinalizedFtor(),
|
||||
NotifyFreedFtor NotifyFreed = NotifyFreedFtor())
|
||||
: ES(ES), GetResources(std::move(GetResources)),
|
||||
NotifyLoaded(std::move(NotifyLoaded)),
|
||||
NotifyFinalized(std::move(NotifyFinalized)),
|
||||
NotifyFreed(std::move(NotifyFreed)), ProcessAllSections(false) {}
|
||||
|
||||
/// Set the 'ProcessAllSections' flag.
|
||||
///
|
||||
/// If set to true, all sections in each object file will be allocated using
|
||||
/// the memory manager, rather than just the sections required for execution.
|
||||
///
|
||||
/// This is kludgy, and may be removed in the future.
|
||||
void setProcessAllSections(bool ProcessAllSections) {
|
||||
this->ProcessAllSections = ProcessAllSections;
|
||||
}
|
||||
|
||||
/// Add an object to the JIT.
|
||||
Error addObject(VModuleKey K, ObjectPtr ObjBuffer) {
|
||||
|
||||
auto Obj =
|
||||
object::ObjectFile::createObjectFile(ObjBuffer->getMemBufferRef());
|
||||
if (!Obj)
|
||||
return Obj.takeError();
|
||||
|
||||
assert(!LinkedObjects.count(K) && "VModuleKey already in use");
|
||||
|
||||
auto R = GetResources(K);
|
||||
|
||||
LinkedObjects[K] = createLinkedObject(
|
||||
*this, K, OwnedObject(std::move(*Obj), std::move(ObjBuffer)),
|
||||
std::move(R.MemMgr), std::move(R.Resolver), ProcessAllSections);
|
||||
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
/// Remove the object associated with VModuleKey K.
|
||||
///
|
||||
/// All memory allocated for the object will be freed, and the sections and
|
||||
/// symbols it provided will no longer be available. No attempt is made to
|
||||
/// re-emit the missing symbols, and any use of these symbols (directly or
|
||||
/// indirectly) will result in undefined behavior. If dependence tracking is
|
||||
/// required to detect or resolve such issues it should be added at a higher
|
||||
/// layer.
|
||||
Error removeObject(VModuleKey K) {
|
||||
assert(LinkedObjects.count(K) && "VModuleKey not associated with object");
|
||||
// How do we invalidate the symbols in H?
|
||||
LinkedObjects.erase(K);
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
/// Search for the given named symbol.
|
||||
/// @param Name The name of the symbol to search for.
|
||||
/// @param ExportedSymbolsOnly If true, search only for exported symbols.
|
||||
/// @return A handle for the given named symbol, if it exists.
|
||||
JITSymbol findSymbol(StringRef Name, bool ExportedSymbolsOnly) {
|
||||
for (auto &KV : LinkedObjects)
|
||||
if (auto Sym = KV.second->getSymbol(Name, ExportedSymbolsOnly))
|
||||
return Sym;
|
||||
else if (auto Err = Sym.takeError())
|
||||
return std::move(Err);
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/// Search for the given named symbol in the context of the loaded
|
||||
/// object represented by the VModuleKey K.
|
||||
/// @param K The VModuleKey for the object to search in.
|
||||
/// @param Name The name of the symbol to search for.
|
||||
/// @param ExportedSymbolsOnly If true, search only for exported symbols.
|
||||
/// @return A handle for the given named symbol, if it is found in the
|
||||
/// given object.
|
||||
JITSymbol findSymbolIn(VModuleKey K, StringRef Name,
|
||||
bool ExportedSymbolsOnly) {
|
||||
assert(LinkedObjects.count(K) && "VModuleKey not associated with object");
|
||||
return LinkedObjects[K]->getSymbol(Name, ExportedSymbolsOnly);
|
||||
}
|
||||
|
||||
/// Map section addresses for the object associated with the
|
||||
/// VModuleKey K.
|
||||
void mapSectionAddress(VModuleKey K, const void *LocalAddress,
|
||||
JITTargetAddress TargetAddr) {
|
||||
assert(LinkedObjects.count(K) && "VModuleKey not associated with object");
|
||||
LinkedObjects[K]->mapSectionAddress(LocalAddress, TargetAddr);
|
||||
}
|
||||
|
||||
/// Immediately emit and finalize the object represented by the given
|
||||
/// VModuleKey.
|
||||
/// @param K VModuleKey for object to emit/finalize.
|
||||
Error emitAndFinalize(VModuleKey K) {
|
||||
assert(LinkedObjects.count(K) && "VModuleKey not associated with object");
|
||||
return LinkedObjects[K]->finalize();
|
||||
}
|
||||
|
||||
private:
|
||||
ExecutionSession &ES;
|
||||
|
||||
ResourcesGetter GetResources;
|
||||
NotifyLoadedFtor NotifyLoaded;
|
||||
NotifyFinalizedFtor NotifyFinalized;
|
||||
NotifyFreedFtor NotifyFreed;
|
||||
|
||||
// NB! `LinkedObjects` needs to be destroyed before `NotifyFreed` because
|
||||
// `~ConcreteLinkedObject` calls `NotifyFreed`
|
||||
std::map<VModuleKey, std::unique_ptr<LinkedObject>> LinkedObjects;
|
||||
bool ProcessAllSections = false;
|
||||
};
|
||||
|
||||
} // end namespace orc
|
||||
} // end namespace llvm
|
||||
|
||||
|
@ -1,564 +0,0 @@
|
||||
//===------ RemoteObjectLayer.h - Forwards objs to a remote -----*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Forwards objects to a remote object layer via RPC.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_EXECUTIONENGINE_ORC_REMOTEOBJECTLAYER_H
|
||||
#define LLVM_EXECUTIONENGINE_ORC_REMOTEOBJECTLAYER_H
|
||||
|
||||
#include "llvm/ExecutionEngine/Orc/Core.h"
|
||||
#include "llvm/ExecutionEngine/Orc/LambdaResolver.h"
|
||||
#include "llvm/ExecutionEngine/Orc/OrcRemoteTargetRPCAPI.h"
|
||||
#include "llvm/Object/ObjectFile.h"
|
||||
#include <map>
|
||||
|
||||
namespace llvm {
|
||||
namespace orc {
|
||||
|
||||
/// RPC API needed by RemoteObjectClientLayer and RemoteObjectServerLayer.
|
||||
class RemoteObjectLayerAPI {
|
||||
public:
|
||||
|
||||
using ObjHandleT = remote::ResourceIdMgr::ResourceId;
|
||||
|
||||
protected:
|
||||
|
||||
using RemoteSymbolId = remote::ResourceIdMgr::ResourceId;
|
||||
using RemoteSymbol = std::pair<RemoteSymbolId, JITSymbolFlags>;
|
||||
|
||||
public:
|
||||
|
||||
using BadSymbolHandleError = remote::ResourceNotFound<RemoteSymbolId>;
|
||||
using BadObjectHandleError = remote::ResourceNotFound<ObjHandleT>;
|
||||
|
||||
protected:
|
||||
|
||||
static const ObjHandleT InvalidObjectHandleId = 0;
|
||||
static const RemoteSymbolId NullSymbolId = 0;
|
||||
|
||||
class AddObject
|
||||
: public rpc::Function<AddObject, Expected<ObjHandleT>(std::string)> {
|
||||
public:
|
||||
static const char *getName() { return "AddObject"; }
|
||||
};
|
||||
|
||||
class RemoveObject
|
||||
: public rpc::Function<RemoveObject, Error(ObjHandleT)> {
|
||||
public:
|
||||
static const char *getName() { return "RemoveObject"; }
|
||||
};
|
||||
|
||||
class FindSymbol
|
||||
: public rpc::Function<FindSymbol, Expected<RemoteSymbol>(std::string,
|
||||
bool)> {
|
||||
public:
|
||||
static const char *getName() { return "FindSymbol"; }
|
||||
};
|
||||
|
||||
class FindSymbolIn
|
||||
: public rpc::Function<FindSymbolIn,
|
||||
Expected<RemoteSymbol>(ObjHandleT, std::string,
|
||||
bool)> {
|
||||
public:
|
||||
static const char *getName() { return "FindSymbolIn"; }
|
||||
};
|
||||
|
||||
class EmitAndFinalize
|
||||
: public rpc::Function<EmitAndFinalize,
|
||||
Error(ObjHandleT)> {
|
||||
public:
|
||||
static const char *getName() { return "EmitAndFinalize"; }
|
||||
};
|
||||
|
||||
class Lookup
|
||||
: public rpc::Function<Lookup,
|
||||
Expected<RemoteSymbol>(ObjHandleT, std::string)> {
|
||||
public:
|
||||
static const char *getName() { return "Lookup"; }
|
||||
};
|
||||
|
||||
class LookupInLogicalDylib
|
||||
: public rpc::Function<LookupInLogicalDylib,
|
||||
Expected<RemoteSymbol>(ObjHandleT, std::string)> {
|
||||
public:
|
||||
static const char *getName() { return "LookupInLogicalDylib"; }
|
||||
};
|
||||
|
||||
class ReleaseRemoteSymbol
|
||||
: public rpc::Function<ReleaseRemoteSymbol, Error(RemoteSymbolId)> {
|
||||
public:
|
||||
static const char *getName() { return "ReleaseRemoteSymbol"; }
|
||||
};
|
||||
|
||||
class MaterializeRemoteSymbol
|
||||
: public rpc::Function<MaterializeRemoteSymbol,
|
||||
Expected<JITTargetAddress>(RemoteSymbolId)> {
|
||||
public:
|
||||
static const char *getName() { return "MaterializeRemoteSymbol"; }
|
||||
};
|
||||
};
|
||||
|
||||
/// Base class containing common utilities for RemoteObjectClientLayer and
|
||||
/// RemoteObjectServerLayer.
|
||||
template <typename RPCEndpoint>
|
||||
class RemoteObjectLayer : public RemoteObjectLayerAPI {
|
||||
public:
|
||||
|
||||
RemoteObjectLayer(RPCEndpoint &Remote,
|
||||
std::function<void(Error)> ReportError)
|
||||
: Remote(Remote), ReportError(std::move(ReportError)),
|
||||
SymbolIdMgr(NullSymbolId + 1) {
|
||||
using ThisT = RemoteObjectLayer<RPCEndpoint>;
|
||||
Remote.template addHandler<ReleaseRemoteSymbol>(
|
||||
*this, &ThisT::handleReleaseRemoteSymbol);
|
||||
Remote.template addHandler<MaterializeRemoteSymbol>(
|
||||
*this, &ThisT::handleMaterializeRemoteSymbol);
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
/// This class is used as the symbol materializer for JITSymbols returned by
|
||||
/// RemoteObjectLayerClient/RemoteObjectLayerServer -- the materializer knows
|
||||
/// how to call back to the other RPC endpoint to get the address when
|
||||
/// requested.
|
||||
class RemoteSymbolMaterializer {
|
||||
public:
|
||||
|
||||
/// Construct a RemoteSymbolMaterializer for the given RemoteObjectLayer
|
||||
/// with the given Id.
|
||||
RemoteSymbolMaterializer(RemoteObjectLayer &C,
|
||||
RemoteSymbolId Id)
|
||||
: C(C), Id(Id) {}
|
||||
|
||||
RemoteSymbolMaterializer(RemoteSymbolMaterializer &&Other)
|
||||
: C(Other.C), Id(Other.Id) {
|
||||
Other.Id = 0;
|
||||
}
|
||||
|
||||
RemoteSymbolMaterializer &operator=(RemoteSymbolMaterializer &&) = delete;
|
||||
|
||||
/// Release the remote symbol.
|
||||
~RemoteSymbolMaterializer() {
|
||||
if (Id)
|
||||
C.releaseRemoteSymbol(Id);
|
||||
}
|
||||
|
||||
/// Materialize the symbol on the remote and get its address.
|
||||
Expected<JITTargetAddress> materialize() {
|
||||
auto Addr = C.materializeRemoteSymbol(Id);
|
||||
Id = 0;
|
||||
return Addr;
|
||||
}
|
||||
|
||||
private:
|
||||
RemoteObjectLayer &C;
|
||||
RemoteSymbolId Id;
|
||||
};
|
||||
|
||||
/// Convenience function for getting a null remote symbol value.
|
||||
RemoteSymbol nullRemoteSymbol() {
|
||||
return RemoteSymbol(0, JITSymbolFlags());
|
||||
}
|
||||
|
||||
/// Creates a StringError that contains a copy of Err's log message, then
|
||||
/// sends that StringError to ReportError.
|
||||
///
|
||||
/// This allows us to locally log error messages for errors that will actually
|
||||
/// be delivered to the remote.
|
||||
Error teeLog(Error Err) {
|
||||
return handleErrors(std::move(Err),
|
||||
[this](std::unique_ptr<ErrorInfoBase> EIB) {
|
||||
ReportError(make_error<StringError>(
|
||||
EIB->message(),
|
||||
EIB->convertToErrorCode()));
|
||||
return Error(std::move(EIB));
|
||||
});
|
||||
}
|
||||
|
||||
Error badRemoteSymbolIdError(RemoteSymbolId Id) {
|
||||
return make_error<BadSymbolHandleError>(Id, "Remote JIT Symbol");
|
||||
}
|
||||
|
||||
Error badObjectHandleError(ObjHandleT H) {
|
||||
return make_error<RemoteObjectLayerAPI::BadObjectHandleError>(
|
||||
H, "Bad object handle");
|
||||
}
|
||||
|
||||
/// Create a RemoteSymbol wrapping the given JITSymbol.
|
||||
Expected<RemoteSymbol> jitSymbolToRemote(JITSymbol Sym) {
|
||||
if (Sym) {
|
||||
auto Id = SymbolIdMgr.getNext();
|
||||
auto Flags = Sym.getFlags();
|
||||
assert(!InUseSymbols.count(Id) && "Symbol id already in use");
|
||||
InUseSymbols.insert(std::make_pair(Id, std::move(Sym)));
|
||||
return RemoteSymbol(Id, Flags);
|
||||
} else if (auto Err = Sym.takeError())
|
||||
return teeLog(std::move(Err));
|
||||
// else...
|
||||
return nullRemoteSymbol();
|
||||
}
|
||||
|
||||
/// Convert an Expected<RemoteSymbol> to a JITSymbol.
|
||||
JITSymbol remoteToJITSymbol(Expected<RemoteSymbol> RemoteSymOrErr) {
|
||||
if (RemoteSymOrErr) {
|
||||
auto &RemoteSym = *RemoteSymOrErr;
|
||||
if (RemoteSym == nullRemoteSymbol())
|
||||
return nullptr;
|
||||
// else...
|
||||
RemoteSymbolMaterializer RSM(*this, RemoteSym.first);
|
||||
auto Sym = JITSymbol(
|
||||
[RSM = std::move(RSM)]() mutable { return RSM.materialize(); },
|
||||
RemoteSym.second);
|
||||
return Sym;
|
||||
} else
|
||||
return RemoteSymOrErr.takeError();
|
||||
}
|
||||
|
||||
RPCEndpoint &Remote;
|
||||
std::function<void(Error)> ReportError;
|
||||
|
||||
private:
|
||||
|
||||
/// Notify the remote to release the given JITSymbol.
|
||||
void releaseRemoteSymbol(RemoteSymbolId Id) {
|
||||
if (auto Err = Remote.template callB<ReleaseRemoteSymbol>(Id))
|
||||
ReportError(std::move(Err));
|
||||
}
|
||||
|
||||
/// Notify the remote to materialize the JITSymbol with the given Id and
|
||||
/// return its address.
|
||||
Expected<JITTargetAddress> materializeRemoteSymbol(RemoteSymbolId Id) {
|
||||
return Remote.template callB<MaterializeRemoteSymbol>(Id);
|
||||
}
|
||||
|
||||
/// Release the JITSymbol with the given Id.
|
||||
Error handleReleaseRemoteSymbol(RemoteSymbolId Id) {
|
||||
auto SI = InUseSymbols.find(Id);
|
||||
if (SI != InUseSymbols.end()) {
|
||||
InUseSymbols.erase(SI);
|
||||
return Error::success();
|
||||
} else
|
||||
return teeLog(badRemoteSymbolIdError(Id));
|
||||
}
|
||||
|
||||
/// Run the materializer for the JITSymbol with the given Id and return its
|
||||
/// address.
|
||||
Expected<JITTargetAddress> handleMaterializeRemoteSymbol(RemoteSymbolId Id) {
|
||||
auto SI = InUseSymbols.find(Id);
|
||||
if (SI != InUseSymbols.end()) {
|
||||
auto AddrOrErr = SI->second.getAddress();
|
||||
InUseSymbols.erase(SI);
|
||||
SymbolIdMgr.release(Id);
|
||||
if (AddrOrErr)
|
||||
return *AddrOrErr;
|
||||
else
|
||||
return teeLog(AddrOrErr.takeError());
|
||||
} else {
|
||||
return teeLog(badRemoteSymbolIdError(Id));
|
||||
}
|
||||
}
|
||||
|
||||
remote::ResourceIdMgr SymbolIdMgr;
|
||||
std::map<RemoteSymbolId, JITSymbol> InUseSymbols;
|
||||
};
|
||||
|
||||
/// RemoteObjectClientLayer forwards the ORC Object Layer API over an RPC
|
||||
/// connection.
|
||||
///
|
||||
/// This class can be used as the base layer of a JIT stack on the client and
|
||||
/// will forward operations to a corresponding RemoteObjectServerLayer on the
|
||||
/// server (which can be composed on top of a "real" object layer like
|
||||
/// RTDyldObjectLinkingLayer to actually carry out the operations).
|
||||
///
|
||||
/// Sending relocatable objects to the server (rather than fully relocated
|
||||
/// bits) allows JIT'd code to be cached on the server side and re-used in
|
||||
/// subsequent JIT sessions.
|
||||
template <typename RPCEndpoint>
|
||||
class RemoteObjectClientLayer : public RemoteObjectLayer<RPCEndpoint> {
|
||||
private:
|
||||
|
||||
using AddObject = RemoteObjectLayerAPI::AddObject;
|
||||
using RemoveObject = RemoteObjectLayerAPI::RemoveObject;
|
||||
using FindSymbol = RemoteObjectLayerAPI::FindSymbol;
|
||||
using FindSymbolIn = RemoteObjectLayerAPI::FindSymbolIn;
|
||||
using EmitAndFinalize = RemoteObjectLayerAPI::EmitAndFinalize;
|
||||
using Lookup = RemoteObjectLayerAPI::Lookup;
|
||||
using LookupInLogicalDylib = RemoteObjectLayerAPI::LookupInLogicalDylib;
|
||||
|
||||
using RemoteObjectLayer<RPCEndpoint>::teeLog;
|
||||
using RemoteObjectLayer<RPCEndpoint>::badObjectHandleError;
|
||||
using RemoteObjectLayer<RPCEndpoint>::remoteToJITSymbol;
|
||||
|
||||
public:
|
||||
|
||||
using ObjHandleT = RemoteObjectLayerAPI::ObjHandleT;
|
||||
using RemoteSymbol = RemoteObjectLayerAPI::RemoteSymbol;
|
||||
|
||||
using ObjectPtr = std::unique_ptr<MemoryBuffer>;
|
||||
|
||||
/// Create a RemoteObjectClientLayer that communicates with a
|
||||
/// RemoteObjectServerLayer instance via the given RPCEndpoint.
|
||||
///
|
||||
/// The ReportError functor can be used locally log errors that are intended
|
||||
/// to be sent sent
|
||||
LLVM_ATTRIBUTE_DEPRECATED(
|
||||
RemoteObjectClientLayer(RPCEndpoint &Remote,
|
||||
std::function<void(Error)> ReportError),
|
||||
"ORCv1 layers (including RemoteObjectClientLayer) are deprecated. Please "
|
||||
"use "
|
||||
"ORCv2 (see docs/ORCv2.rst)");
|
||||
|
||||
RemoteObjectClientLayer(ORCv1DeprecationAcknowledgement, RPCEndpoint &Remote,
|
||||
std::function<void(Error)> ReportError)
|
||||
: RemoteObjectLayer<RPCEndpoint>(Remote, std::move(ReportError)) {
|
||||
using ThisT = RemoteObjectClientLayer<RPCEndpoint>;
|
||||
Remote.template addHandler<Lookup>(*this, &ThisT::lookup);
|
||||
Remote.template addHandler<LookupInLogicalDylib>(
|
||||
*this, &ThisT::lookupInLogicalDylib);
|
||||
}
|
||||
|
||||
/// Add an object to the JIT.
|
||||
///
|
||||
/// @return A handle that can be used to refer to the loaded object (for
|
||||
/// symbol searching, finalization, freeing memory, etc.).
|
||||
Expected<ObjHandleT>
|
||||
addObject(ObjectPtr ObjBuffer,
|
||||
std::shared_ptr<LegacyJITSymbolResolver> Resolver) {
|
||||
if (auto HandleOrErr =
|
||||
this->Remote.template callB<AddObject>(ObjBuffer->getBuffer())) {
|
||||
auto &Handle = *HandleOrErr;
|
||||
// FIXME: Return an error for this:
|
||||
assert(!Resolvers.count(Handle) && "Handle already in use?");
|
||||
Resolvers[Handle] = std::move(Resolver);
|
||||
return Handle;
|
||||
} else
|
||||
return HandleOrErr.takeError();
|
||||
}
|
||||
|
||||
/// Remove the given object from the JIT.
|
||||
Error removeObject(ObjHandleT H) {
|
||||
return this->Remote.template callB<RemoveObject>(H);
|
||||
}
|
||||
|
||||
/// Search for the given named symbol.
|
||||
JITSymbol findSymbol(StringRef Name, bool ExportedSymbolsOnly) {
|
||||
return remoteToJITSymbol(
|
||||
this->Remote.template callB<FindSymbol>(Name,
|
||||
ExportedSymbolsOnly));
|
||||
}
|
||||
|
||||
/// Search for the given named symbol within the given context.
|
||||
JITSymbol findSymbolIn(ObjHandleT H, StringRef Name, bool ExportedSymbolsOnly) {
|
||||
return remoteToJITSymbol(
|
||||
this->Remote.template callB<FindSymbolIn>(H, Name,
|
||||
ExportedSymbolsOnly));
|
||||
}
|
||||
|
||||
/// Immediately emit and finalize the object with the given handle.
|
||||
Error emitAndFinalize(ObjHandleT H) {
|
||||
return this->Remote.template callB<EmitAndFinalize>(H);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
Expected<RemoteSymbol> lookup(ObjHandleT H, const std::string &Name) {
|
||||
auto RI = Resolvers.find(H);
|
||||
if (RI != Resolvers.end()) {
|
||||
return this->jitSymbolToRemote(RI->second->findSymbol(Name));
|
||||
} else
|
||||
return teeLog(badObjectHandleError(H));
|
||||
}
|
||||
|
||||
Expected<RemoteSymbol> lookupInLogicalDylib(ObjHandleT H,
|
||||
const std::string &Name) {
|
||||
auto RI = Resolvers.find(H);
|
||||
if (RI != Resolvers.end())
|
||||
return this->jitSymbolToRemote(
|
||||
RI->second->findSymbolInLogicalDylib(Name));
|
||||
else
|
||||
return teeLog(badObjectHandleError(H));
|
||||
}
|
||||
|
||||
std::map<remote::ResourceIdMgr::ResourceId,
|
||||
std::shared_ptr<LegacyJITSymbolResolver>>
|
||||
Resolvers;
|
||||
};
|
||||
|
||||
/// RemoteObjectServerLayer acts as a server and handling RPC calls for the
|
||||
/// object layer API from the given RPC connection.
|
||||
///
|
||||
/// This class can be composed on top of a 'real' object layer (e.g.
|
||||
/// RTDyldObjectLinkingLayer) to do the actual work of relocating objects
|
||||
/// and making them executable.
|
||||
template <typename BaseLayerT, typename RPCEndpoint>
|
||||
class RemoteObjectServerLayer : public RemoteObjectLayer<RPCEndpoint> {
|
||||
private:
|
||||
|
||||
using ObjHandleT = RemoteObjectLayerAPI::ObjHandleT;
|
||||
using RemoteSymbol = RemoteObjectLayerAPI::RemoteSymbol;
|
||||
|
||||
using AddObject = RemoteObjectLayerAPI::AddObject;
|
||||
using RemoveObject = RemoteObjectLayerAPI::RemoveObject;
|
||||
using FindSymbol = RemoteObjectLayerAPI::FindSymbol;
|
||||
using FindSymbolIn = RemoteObjectLayerAPI::FindSymbolIn;
|
||||
using EmitAndFinalize = RemoteObjectLayerAPI::EmitAndFinalize;
|
||||
using Lookup = RemoteObjectLayerAPI::Lookup;
|
||||
using LookupInLogicalDylib = RemoteObjectLayerAPI::LookupInLogicalDylib;
|
||||
|
||||
using RemoteObjectLayer<RPCEndpoint>::teeLog;
|
||||
using RemoteObjectLayer<RPCEndpoint>::badObjectHandleError;
|
||||
using RemoteObjectLayer<RPCEndpoint>::remoteToJITSymbol;
|
||||
|
||||
public:
|
||||
|
||||
/// Create a RemoteObjectServerLayer with the given base layer (which must be
|
||||
/// an object layer), RPC endpoint, and error reporter function.
|
||||
LLVM_ATTRIBUTE_DEPRECATED(
|
||||
RemoteObjectServerLayer(BaseLayerT &BaseLayer, RPCEndpoint &Remote,
|
||||
std::function<void(Error)> ReportError),
|
||||
"ORCv1 layers (including RemoteObjectServerLayer) are deprecated. Please "
|
||||
"use "
|
||||
"ORCv2 (see docs/ORCv2.rst)");
|
||||
|
||||
RemoteObjectServerLayer(ORCv1DeprecationAcknowledgement,
|
||||
BaseLayerT &BaseLayer, RPCEndpoint &Remote,
|
||||
std::function<void(Error)> ReportError)
|
||||
: RemoteObjectLayer<RPCEndpoint>(Remote, std::move(ReportError)),
|
||||
BaseLayer(BaseLayer), HandleIdMgr(1) {
|
||||
using ThisT = RemoteObjectServerLayer<BaseLayerT, RPCEndpoint>;
|
||||
|
||||
Remote.template addHandler<AddObject>(*this, &ThisT::addObject);
|
||||
Remote.template addHandler<RemoveObject>(*this, &ThisT::removeObject);
|
||||
Remote.template addHandler<FindSymbol>(*this, &ThisT::findSymbol);
|
||||
Remote.template addHandler<FindSymbolIn>(*this, &ThisT::findSymbolIn);
|
||||
Remote.template addHandler<EmitAndFinalize>(*this, &ThisT::emitAndFinalize);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
class StringMemoryBuffer : public MemoryBuffer {
|
||||
public:
|
||||
StringMemoryBuffer(std::string Buffer)
|
||||
: Buffer(std::move(Buffer)) {
|
||||
init(this->Buffer.data(), this->Buffer.data() + this->Buffer.size(),
|
||||
false);
|
||||
}
|
||||
|
||||
BufferKind getBufferKind() const override { return MemoryBuffer_Malloc; }
|
||||
private:
|
||||
std::string Buffer;
|
||||
};
|
||||
|
||||
JITSymbol lookup(ObjHandleT Id, const std::string &Name) {
|
||||
return remoteToJITSymbol(
|
||||
this->Remote.template callB<Lookup>(Id, Name));
|
||||
}
|
||||
|
||||
JITSymbol lookupInLogicalDylib(ObjHandleT Id, const std::string &Name) {
|
||||
return remoteToJITSymbol(
|
||||
this->Remote.template callB<LookupInLogicalDylib>(Id, Name));
|
||||
}
|
||||
|
||||
Expected<ObjHandleT> addObject(std::string ObjBuffer) {
|
||||
auto Buffer = std::make_unique<StringMemoryBuffer>(std::move(ObjBuffer));
|
||||
auto Id = HandleIdMgr.getNext();
|
||||
assert(!BaseLayerHandles.count(Id) && "Id already in use?");
|
||||
|
||||
auto Resolver = createLambdaResolver(
|
||||
AcknowledgeORCv1Deprecation,
|
||||
[this, Id](const std::string &Name) { return lookup(Id, Name); },
|
||||
[this, Id](const std::string &Name) {
|
||||
return lookupInLogicalDylib(Id, Name);
|
||||
});
|
||||
|
||||
if (auto HandleOrErr =
|
||||
BaseLayer.addObject(std::move(Buffer), std::move(Resolver))) {
|
||||
BaseLayerHandles[Id] = std::move(*HandleOrErr);
|
||||
return Id;
|
||||
} else
|
||||
return teeLog(HandleOrErr.takeError());
|
||||
}
|
||||
|
||||
Error removeObject(ObjHandleT H) {
|
||||
auto HI = BaseLayerHandles.find(H);
|
||||
if (HI != BaseLayerHandles.end()) {
|
||||
if (auto Err = BaseLayer.removeObject(HI->second))
|
||||
return teeLog(std::move(Err));
|
||||
return Error::success();
|
||||
} else
|
||||
return teeLog(badObjectHandleError(H));
|
||||
}
|
||||
|
||||
Expected<RemoteSymbol> findSymbol(const std::string &Name,
|
||||
bool ExportedSymbolsOnly) {
|
||||
if (auto Sym = BaseLayer.findSymbol(Name, ExportedSymbolsOnly))
|
||||
return this->jitSymbolToRemote(std::move(Sym));
|
||||
else if (auto Err = Sym.takeError())
|
||||
return teeLog(std::move(Err));
|
||||
return this->nullRemoteSymbol();
|
||||
}
|
||||
|
||||
Expected<RemoteSymbol> findSymbolIn(ObjHandleT H, const std::string &Name,
|
||||
bool ExportedSymbolsOnly) {
|
||||
auto HI = BaseLayerHandles.find(H);
|
||||
if (HI != BaseLayerHandles.end()) {
|
||||
if (auto Sym = BaseLayer.findSymbolIn(HI->second, Name, ExportedSymbolsOnly))
|
||||
return this->jitSymbolToRemote(std::move(Sym));
|
||||
else if (auto Err = Sym.takeError())
|
||||
return teeLog(std::move(Err));
|
||||
return this->nullRemoteSymbol();
|
||||
} else
|
||||
return teeLog(badObjectHandleError(H));
|
||||
}
|
||||
|
||||
Error emitAndFinalize(ObjHandleT H) {
|
||||
auto HI = BaseLayerHandles.find(H);
|
||||
if (HI != BaseLayerHandles.end()) {
|
||||
if (auto Err = BaseLayer.emitAndFinalize(HI->second))
|
||||
return teeLog(std::move(Err));
|
||||
return Error::success();
|
||||
} else
|
||||
return teeLog(badObjectHandleError(H));
|
||||
}
|
||||
|
||||
BaseLayerT &BaseLayer;
|
||||
remote::ResourceIdMgr HandleIdMgr;
|
||||
std::map<ObjHandleT, typename BaseLayerT::ObjHandleT> BaseLayerHandles;
|
||||
};
|
||||
|
||||
template <typename RPCEndpoint>
|
||||
RemoteObjectClientLayer<RPCEndpoint>::RemoteObjectClientLayer(
|
||||
RPCEndpoint &Remote, std::function<void(Error)> ReportError)
|
||||
: RemoteObjectLayer<RPCEndpoint>(Remote, std::move(ReportError)) {
|
||||
using ThisT = RemoteObjectClientLayer<RPCEndpoint>;
|
||||
Remote.template addHandler<Lookup>(*this, &ThisT::lookup);
|
||||
Remote.template addHandler<LookupInLogicalDylib>(
|
||||
*this, &ThisT::lookupInLogicalDylib);
|
||||
}
|
||||
|
||||
template <typename BaseLayerT, typename RPCEndpoint>
|
||||
RemoteObjectServerLayer<BaseLayerT, RPCEndpoint>::RemoteObjectServerLayer(
|
||||
BaseLayerT &BaseLayer, RPCEndpoint &Remote,
|
||||
std::function<void(Error)> ReportError)
|
||||
: RemoteObjectLayer<RPCEndpoint>(Remote, std::move(ReportError)),
|
||||
BaseLayer(BaseLayer), HandleIdMgr(1) {
|
||||
using ThisT = RemoteObjectServerLayer<BaseLayerT, RPCEndpoint>;
|
||||
|
||||
Remote.template addHandler<AddObject>(*this, &ThisT::addObject);
|
||||
Remote.template addHandler<RemoveObject>(*this, &ThisT::removeObject);
|
||||
Remote.template addHandler<FindSymbol>(*this, &ThisT::findSymbol);
|
||||
Remote.template addHandler<FindSymbolIn>(*this, &ThisT::findSymbolIn);
|
||||
Remote.template addHandler<EmitAndFinalize>(*this, &ThisT::emitAndFinalize);
|
||||
}
|
||||
|
||||
} // end namespace orc
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_EXECUTIONENGINE_ORC_REMOTEOBJECTLAYER_H
|
@ -53,11 +53,6 @@ ExecutionEngine *(*ExecutionEngine::MCJITCtor)(
|
||||
std::shared_ptr<LegacyJITSymbolResolver> Resolver,
|
||||
std::unique_ptr<TargetMachine> TM) = nullptr;
|
||||
|
||||
ExecutionEngine *(*ExecutionEngine::OrcMCJITReplacementCtor)(
|
||||
std::string *ErrorStr, std::shared_ptr<MCJITMemoryManager> MemMgr,
|
||||
std::shared_ptr<LegacyJITSymbolResolver> Resolver,
|
||||
std::unique_ptr<TargetMachine> TM) = nullptr;
|
||||
|
||||
ExecutionEngine *(*ExecutionEngine::InterpCtor)(std::unique_ptr<Module> M,
|
||||
std::string *ErrorStr) =nullptr;
|
||||
|
||||
@ -476,8 +471,7 @@ EngineBuilder::EngineBuilder() : EngineBuilder(nullptr) {}
|
||||
|
||||
EngineBuilder::EngineBuilder(std::unique_ptr<Module> M)
|
||||
: M(std::move(M)), WhichEngine(EngineKind::Either), ErrorStr(nullptr),
|
||||
OptLevel(CodeGenOpt::Default), MemMgr(nullptr), Resolver(nullptr),
|
||||
UseOrcMCJITReplacement(false) {
|
||||
OptLevel(CodeGenOpt::Default), MemMgr(nullptr), Resolver(nullptr) {
|
||||
// IR module verification is enabled by default in debug builds, and disabled
|
||||
// by default in release builds.
|
||||
#ifndef NDEBUG
|
||||
@ -540,12 +534,7 @@ ExecutionEngine *EngineBuilder::create(TargetMachine *TM) {
|
||||
}
|
||||
|
||||
ExecutionEngine *EE = nullptr;
|
||||
if (ExecutionEngine::OrcMCJITReplacementCtor && UseOrcMCJITReplacement) {
|
||||
EE = ExecutionEngine::OrcMCJITReplacementCtor(ErrorStr, std::move(MemMgr),
|
||||
std::move(Resolver),
|
||||
std::move(TheTM));
|
||||
EE->addModule(std::move(M));
|
||||
} else if (ExecutionEngine::MCJITCtor)
|
||||
if (ExecutionEngine::MCJITCtor)
|
||||
EE = ExecutionEngine::MCJITCtor(std::move(M), ErrorStr, std::move(MemMgr),
|
||||
std::move(Resolver), std::move(TheTM));
|
||||
|
||||
|
@ -9,18 +9,14 @@ add_llvm_component_library(LLVMOrcJIT
|
||||
IRTransformLayer.cpp
|
||||
JITTargetMachineBuilder.cpp
|
||||
LazyReexports.cpp
|
||||
Legacy.cpp
|
||||
Layer.cpp
|
||||
LLJIT.cpp
|
||||
MachOPlatform.cpp
|
||||
Mangling.cpp
|
||||
NullResolver.cpp
|
||||
ObjectLinkingLayer.cpp
|
||||
ObjectTransformLayer.cpp
|
||||
OrcABISupport.cpp
|
||||
OrcCBindings.cpp
|
||||
OrcV2CBindings.cpp
|
||||
OrcMCJITReplacement.cpp
|
||||
RTDyldObjectLinkingLayer.cpp
|
||||
Speculation.cpp
|
||||
SpeculateAnalyses.cpp
|
||||
|
@ -137,8 +137,6 @@ void AsynchronousSymbolQuery::handleComplete() {
|
||||
TmpNotifyComplete(std::move(ResolvedSymbols));
|
||||
}
|
||||
|
||||
bool AsynchronousSymbolQuery::canStillFail() { return !!NotifyComplete; }
|
||||
|
||||
void AsynchronousSymbolQuery::handleFailed(Error Err) {
|
||||
assert(QueryRegistrations.empty() && ResolvedSymbols.empty() &&
|
||||
OutstandingSymbolsCount == 0 &&
|
||||
@ -1406,132 +1404,6 @@ Error JITDylib::lodgeQueryImpl(MaterializationUnitList &MUs,
|
||||
});
|
||||
}
|
||||
|
||||
Expected<SymbolNameSet>
|
||||
JITDylib::legacyLookup(std::shared_ptr<AsynchronousSymbolQuery> Q,
|
||||
SymbolNameSet Names) {
|
||||
assert(Q && "Query can not be null");
|
||||
|
||||
ES.runOutstandingMUs();
|
||||
|
||||
bool QueryComplete = false;
|
||||
std::vector<std::unique_ptr<MaterializationUnit>> MUs;
|
||||
|
||||
SymbolLookupSet Unresolved(Names);
|
||||
auto Err = ES.runSessionLocked([&, this]() -> Error {
|
||||
QueryComplete = lookupImpl(Q, MUs, Unresolved);
|
||||
|
||||
// Run any definition generators.
|
||||
for (auto &DG : DefGenerators) {
|
||||
|
||||
// Bail out early if we have resolved everything.
|
||||
if (Unresolved.empty())
|
||||
break;
|
||||
|
||||
assert(!QueryComplete && "query complete but unresolved symbols remain?");
|
||||
if (auto Err = DG->tryToGenerate(LookupKind::Static, *this,
|
||||
JITDylibLookupFlags::MatchAllSymbols,
|
||||
Unresolved))
|
||||
return Err;
|
||||
|
||||
if (!Unresolved.empty())
|
||||
QueryComplete = lookupImpl(Q, MUs, Unresolved);
|
||||
}
|
||||
return Error::success();
|
||||
});
|
||||
|
||||
if (Err)
|
||||
return std::move(Err);
|
||||
|
||||
assert((MUs.empty() || !QueryComplete) &&
|
||||
"If action flags are set, there should be no work to do (so no MUs)");
|
||||
|
||||
if (QueryComplete)
|
||||
Q->handleComplete();
|
||||
|
||||
// FIXME: Swap back to the old code below once RuntimeDyld works with
|
||||
// callbacks from asynchronous queries.
|
||||
// Add MUs to the OutstandingMUs list.
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> Lock(ES.OutstandingMUsMutex);
|
||||
auto ThisJD = shared_from_this();
|
||||
for (auto &MU : MUs) {
|
||||
auto MR = MU->createMaterializationResponsibility(ThisJD);
|
||||
ES.OutstandingMUs.push_back(make_pair(std::move(MU), std::move(MR)));
|
||||
}
|
||||
}
|
||||
ES.runOutstandingMUs();
|
||||
|
||||
// Dispatch any required MaterializationUnits for materialization.
|
||||
// for (auto &MU : MUs)
|
||||
// ES.dispatchMaterialization(*this, std::move(MU));
|
||||
|
||||
SymbolNameSet RemainingSymbols;
|
||||
for (auto &KV : Unresolved)
|
||||
RemainingSymbols.insert(KV.first);
|
||||
|
||||
return RemainingSymbols;
|
||||
}
|
||||
|
||||
bool JITDylib::lookupImpl(
|
||||
std::shared_ptr<AsynchronousSymbolQuery> &Q,
|
||||
std::vector<std::unique_ptr<MaterializationUnit>> &MUs,
|
||||
SymbolLookupSet &Unresolved) {
|
||||
bool QueryComplete = false;
|
||||
|
||||
std::vector<SymbolStringPtr> ToRemove;
|
||||
Unresolved.forEachWithRemoval(
|
||||
[&](const SymbolStringPtr &Name, SymbolLookupFlags Flags) -> bool {
|
||||
// Search for the name in Symbols. Skip without removing if not found.
|
||||
auto SymI = Symbols.find(Name);
|
||||
if (SymI == Symbols.end())
|
||||
return false;
|
||||
|
||||
// If the symbol is already in the required state then notify the query
|
||||
// and remove.
|
||||
if (SymI->second.getState() >= Q->getRequiredState()) {
|
||||
Q->notifySymbolMetRequiredState(Name, SymI->second.getSymbol());
|
||||
if (Q->isComplete())
|
||||
QueryComplete = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
// If the symbol is lazy, get the MaterialiaztionUnit for it.
|
||||
if (SymI->second.hasMaterializerAttached()) {
|
||||
assert(SymI->second.getAddress() == 0 &&
|
||||
"Lazy symbol should not have a resolved address");
|
||||
auto UMII = UnmaterializedInfos.find(Name);
|
||||
assert(UMII != UnmaterializedInfos.end() &&
|
||||
"Lazy symbol should have UnmaterializedInfo");
|
||||
auto MU = std::move(UMII->second->MU);
|
||||
assert(MU != nullptr && "Materializer should not be null");
|
||||
|
||||
// Kick all symbols associated with this MaterializationUnit into
|
||||
// materializing state.
|
||||
for (auto &KV : MU->getSymbols()) {
|
||||
auto SymK = Symbols.find(KV.first);
|
||||
assert(SymK != Symbols.end() && "Missing symbol table entry");
|
||||
SymK->second.setState(SymbolState::Materializing);
|
||||
SymK->second.setMaterializerAttached(false);
|
||||
UnmaterializedInfos.erase(KV.first);
|
||||
}
|
||||
|
||||
// Add MU to the list of MaterializationUnits to be materialized.
|
||||
MUs.push_back(std::move(MU));
|
||||
}
|
||||
|
||||
// Add the query to the PendingQueries list.
|
||||
assert(SymI->second.getState() != SymbolState::NeverSearched &&
|
||||
SymI->second.getState() != SymbolState::Ready &&
|
||||
"By this line the symbol should be materializing");
|
||||
auto &MI = MaterializingInfos[Name];
|
||||
MI.addQuery(Q);
|
||||
Q->addQueryDependence(*this, Name);
|
||||
return true;
|
||||
});
|
||||
|
||||
return QueryComplete;
|
||||
}
|
||||
|
||||
void JITDylib::dump(raw_ostream &OS) {
|
||||
ES.runSessionLocked([&, this]() {
|
||||
OS << "JITDylib \"" << JITDylibName << "\" (ES: "
|
||||
@ -1804,88 +1676,6 @@ Expected<JITDylib &> ExecutionSession::createJITDylib(std::string Name) {
|
||||
return JD;
|
||||
}
|
||||
|
||||
void ExecutionSession::legacyFailQuery(AsynchronousSymbolQuery &Q, Error Err) {
|
||||
assert(!!Err && "Error should be in failure state");
|
||||
|
||||
bool SendErrorToQuery;
|
||||
runSessionLocked([&]() {
|
||||
Q.detach();
|
||||
SendErrorToQuery = Q.canStillFail();
|
||||
});
|
||||
|
||||
if (SendErrorToQuery)
|
||||
Q.handleFailed(std::move(Err));
|
||||
else
|
||||
reportError(std::move(Err));
|
||||
}
|
||||
|
||||
Expected<SymbolMap> ExecutionSession::legacyLookup(
|
||||
LegacyAsyncLookupFunction AsyncLookup, SymbolNameSet Names,
|
||||
SymbolState RequiredState,
|
||||
RegisterDependenciesFunction RegisterDependencies) {
|
||||
#if LLVM_ENABLE_THREADS
|
||||
// In the threaded case we use promises to return the results.
|
||||
std::promise<SymbolMap> PromisedResult;
|
||||
Error ResolutionError = Error::success();
|
||||
auto NotifyComplete = [&](Expected<SymbolMap> R) {
|
||||
if (R)
|
||||
PromisedResult.set_value(std::move(*R));
|
||||
else {
|
||||
ErrorAsOutParameter _(&ResolutionError);
|
||||
ResolutionError = R.takeError();
|
||||
PromisedResult.set_value(SymbolMap());
|
||||
}
|
||||
};
|
||||
#else
|
||||
SymbolMap Result;
|
||||
Error ResolutionError = Error::success();
|
||||
|
||||
auto NotifyComplete = [&](Expected<SymbolMap> R) {
|
||||
ErrorAsOutParameter _(&ResolutionError);
|
||||
if (R)
|
||||
Result = std::move(*R);
|
||||
else
|
||||
ResolutionError = R.takeError();
|
||||
};
|
||||
#endif
|
||||
|
||||
auto Query = std::make_shared<AsynchronousSymbolQuery>(
|
||||
SymbolLookupSet(Names), RequiredState, std::move(NotifyComplete));
|
||||
// FIXME: This should be run session locked along with the registration code
|
||||
// and error reporting below.
|
||||
SymbolNameSet UnresolvedSymbols = AsyncLookup(Query, std::move(Names));
|
||||
|
||||
// If the query was lodged successfully then register the dependencies,
|
||||
// otherwise fail it with an error.
|
||||
if (UnresolvedSymbols.empty())
|
||||
RegisterDependencies(Query->QueryRegistrations);
|
||||
else {
|
||||
bool DeliverError = runSessionLocked([&]() {
|
||||
Query->detach();
|
||||
return Query->canStillFail();
|
||||
});
|
||||
auto Err = make_error<SymbolsNotFound>(std::move(UnresolvedSymbols));
|
||||
if (DeliverError)
|
||||
Query->handleFailed(std::move(Err));
|
||||
else
|
||||
reportError(std::move(Err));
|
||||
}
|
||||
|
||||
#if LLVM_ENABLE_THREADS
|
||||
auto ResultFuture = PromisedResult.get_future();
|
||||
auto Result = ResultFuture.get();
|
||||
if (ResolutionError)
|
||||
return std::move(ResolutionError);
|
||||
return std::move(Result);
|
||||
|
||||
#else
|
||||
if (ResolutionError)
|
||||
return std::move(ResolutionError);
|
||||
|
||||
return Result;
|
||||
#endif
|
||||
}
|
||||
|
||||
std::vector<std::shared_ptr<JITDylib>>
|
||||
JITDylib::getDFSLinkOrder(ArrayRef<std::shared_ptr<JITDylib>> JDs) {
|
||||
if (JDs.empty())
|
||||
|
@ -1,68 +0,0 @@
|
||||
//===------- Legacy.cpp - Adapters for ExecutionEngine API interop --------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/ExecutionEngine/Orc/Legacy.h"
|
||||
|
||||
namespace llvm {
|
||||
namespace orc {
|
||||
|
||||
void SymbolResolver::anchor() {}
|
||||
|
||||
JITSymbolResolverAdapter::JITSymbolResolverAdapter(
|
||||
ExecutionSession &ES, SymbolResolver &R, MaterializationResponsibility *MR)
|
||||
: ES(ES), R(R), MR(MR) {}
|
||||
|
||||
void JITSymbolResolverAdapter::lookup(const LookupSet &Symbols,
|
||||
OnResolvedFunction OnResolved) {
|
||||
SymbolNameSet InternedSymbols;
|
||||
for (auto &S : Symbols)
|
||||
InternedSymbols.insert(ES.intern(S));
|
||||
|
||||
auto OnResolvedWithUnwrap = [OnResolved = std::move(OnResolved)](
|
||||
Expected<SymbolMap> InternedResult) mutable {
|
||||
if (!InternedResult) {
|
||||
OnResolved(InternedResult.takeError());
|
||||
return;
|
||||
}
|
||||
|
||||
LookupResult Result;
|
||||
for (auto &KV : *InternedResult)
|
||||
Result[*KV.first] = std::move(KV.second);
|
||||
OnResolved(Result);
|
||||
};
|
||||
|
||||
auto Q = std::make_shared<AsynchronousSymbolQuery>(
|
||||
SymbolLookupSet(InternedSymbols), SymbolState::Resolved,
|
||||
std::move(OnResolvedWithUnwrap));
|
||||
|
||||
auto Unresolved = R.lookup(Q, InternedSymbols);
|
||||
if (Unresolved.empty()) {
|
||||
if (MR)
|
||||
MR->addDependenciesForAll(Q->QueryRegistrations);
|
||||
} else
|
||||
ES.legacyFailQuery(*Q, make_error<SymbolsNotFound>(std::move(Unresolved)));
|
||||
}
|
||||
|
||||
Expected<JITSymbolResolverAdapter::LookupSet>
|
||||
JITSymbolResolverAdapter::getResponsibilitySet(const LookupSet &Symbols) {
|
||||
SymbolNameSet InternedSymbols;
|
||||
for (auto &S : Symbols)
|
||||
InternedSymbols.insert(ES.intern(S));
|
||||
|
||||
auto InternedResult = R.getResponsibilitySet(InternedSymbols);
|
||||
LookupSet Result;
|
||||
for (auto &S : InternedResult) {
|
||||
ResolvedStrings.insert(S);
|
||||
Result.insert(*S);
|
||||
}
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
} // End namespace orc.
|
||||
} // End namespace llvm.
|
@ -1,37 +0,0 @@
|
||||
//===---------- NullResolver.cpp - Reject symbol lookup requests ----------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/ExecutionEngine/Orc/NullResolver.h"
|
||||
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
|
||||
namespace llvm {
|
||||
namespace orc {
|
||||
|
||||
SymbolNameSet NullResolver::getResponsibilitySet(const SymbolNameSet &Symbols) {
|
||||
return Symbols;
|
||||
}
|
||||
|
||||
SymbolNameSet
|
||||
NullResolver::lookup(std::shared_ptr<AsynchronousSymbolQuery> Query,
|
||||
SymbolNameSet Symbols) {
|
||||
assert(Symbols.empty() && "Null resolver: Symbols must be empty");
|
||||
return Symbols;
|
||||
}
|
||||
|
||||
JITSymbol NullLegacyResolver::findSymbol(const std::string &Name) {
|
||||
llvm_unreachable("Unexpected cross-object symbol reference");
|
||||
}
|
||||
|
||||
JITSymbol
|
||||
NullLegacyResolver::findSymbolInLogicalDylib(const std::string &Name) {
|
||||
llvm_unreachable("Unexpected cross-object symbol reference");
|
||||
}
|
||||
|
||||
} // End namespace orc.
|
||||
} // End namespace llvm.
|
@ -1,158 +0,0 @@
|
||||
//===----------- OrcCBindings.cpp - C bindings for the Orc APIs -----------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "OrcCBindingsStack.h"
|
||||
#include "llvm-c/OrcBindings.h"
|
||||
#include "llvm/ExecutionEngine/JITEventListener.h"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
LLVMOrcJITStackRef LLVMOrcCreateInstance(LLVMTargetMachineRef TM) {
|
||||
TargetMachine *TM2(unwrap(TM));
|
||||
|
||||
Triple T(TM2->getTargetTriple());
|
||||
|
||||
auto IndirectStubsMgrBuilder =
|
||||
orc::createLocalIndirectStubsManagerBuilder(T);
|
||||
|
||||
OrcCBindingsStack *JITStack =
|
||||
new OrcCBindingsStack(*TM2, std::move(IndirectStubsMgrBuilder));
|
||||
|
||||
return wrap(JITStack);
|
||||
}
|
||||
|
||||
const char *LLVMOrcGetErrorMsg(LLVMOrcJITStackRef JITStack) {
|
||||
OrcCBindingsStack &J = *unwrap(JITStack);
|
||||
return J.getErrorMessage().c_str();
|
||||
}
|
||||
|
||||
void LLVMOrcGetMangledSymbol(LLVMOrcJITStackRef JITStack, char **MangledName,
|
||||
const char *SymbolName) {
|
||||
OrcCBindingsStack &J = *unwrap(JITStack);
|
||||
std::string Mangled = J.mangle(SymbolName);
|
||||
*MangledName = new char[Mangled.size() + 1];
|
||||
strcpy(*MangledName, Mangled.c_str());
|
||||
}
|
||||
|
||||
void LLVMOrcDisposeMangledSymbol(char *MangledName) { delete[] MangledName; }
|
||||
|
||||
LLVMErrorRef LLVMOrcCreateLazyCompileCallback(
|
||||
LLVMOrcJITStackRef JITStack, LLVMOrcTargetAddress *RetAddr,
|
||||
LLVMOrcLazyCompileCallbackFn Callback, void *CallbackCtx) {
|
||||
OrcCBindingsStack &J = *unwrap(JITStack);
|
||||
if (auto Addr = J.createLazyCompileCallback(Callback, CallbackCtx)) {
|
||||
*RetAddr = *Addr;
|
||||
return LLVMErrorSuccess;
|
||||
} else
|
||||
return wrap(Addr.takeError());
|
||||
}
|
||||
|
||||
LLVMErrorRef LLVMOrcCreateIndirectStub(LLVMOrcJITStackRef JITStack,
|
||||
const char *StubName,
|
||||
LLVMOrcTargetAddress InitAddr) {
|
||||
OrcCBindingsStack &J = *unwrap(JITStack);
|
||||
return wrap(J.createIndirectStub(StubName, InitAddr));
|
||||
}
|
||||
|
||||
LLVMErrorRef LLVMOrcSetIndirectStubPointer(LLVMOrcJITStackRef JITStack,
|
||||
const char *StubName,
|
||||
LLVMOrcTargetAddress NewAddr) {
|
||||
OrcCBindingsStack &J = *unwrap(JITStack);
|
||||
return wrap(J.setIndirectStubPointer(StubName, NewAddr));
|
||||
}
|
||||
|
||||
LLVMErrorRef LLVMOrcAddEagerlyCompiledIR(LLVMOrcJITStackRef JITStack,
|
||||
LLVMOrcModuleHandle *RetHandle,
|
||||
LLVMModuleRef Mod,
|
||||
LLVMOrcSymbolResolverFn SymbolResolver,
|
||||
void *SymbolResolverCtx) {
|
||||
OrcCBindingsStack &J = *unwrap(JITStack);
|
||||
std::unique_ptr<Module> M(unwrap(Mod));
|
||||
if (auto Handle =
|
||||
J.addIRModuleEager(std::move(M), SymbolResolver, SymbolResolverCtx)) {
|
||||
*RetHandle = *Handle;
|
||||
return LLVMErrorSuccess;
|
||||
} else
|
||||
return wrap(Handle.takeError());
|
||||
}
|
||||
|
||||
LLVMErrorRef LLVMOrcAddLazilyCompiledIR(LLVMOrcJITStackRef JITStack,
|
||||
LLVMOrcModuleHandle *RetHandle,
|
||||
LLVMModuleRef Mod,
|
||||
LLVMOrcSymbolResolverFn SymbolResolver,
|
||||
void *SymbolResolverCtx) {
|
||||
OrcCBindingsStack &J = *unwrap(JITStack);
|
||||
std::unique_ptr<Module> M(unwrap(Mod));
|
||||
if (auto Handle =
|
||||
J.addIRModuleLazy(std::move(M), SymbolResolver, SymbolResolverCtx)) {
|
||||
*RetHandle = *Handle;
|
||||
return LLVMErrorSuccess;
|
||||
} else
|
||||
return wrap(Handle.takeError());
|
||||
}
|
||||
|
||||
LLVMErrorRef LLVMOrcAddObjectFile(LLVMOrcJITStackRef JITStack,
|
||||
LLVMOrcModuleHandle *RetHandle,
|
||||
LLVMMemoryBufferRef Obj,
|
||||
LLVMOrcSymbolResolverFn SymbolResolver,
|
||||
void *SymbolResolverCtx) {
|
||||
OrcCBindingsStack &J = *unwrap(JITStack);
|
||||
std::unique_ptr<MemoryBuffer> O(unwrap(Obj));
|
||||
if (auto Handle =
|
||||
J.addObject(std::move(O), SymbolResolver, SymbolResolverCtx)) {
|
||||
*RetHandle = *Handle;
|
||||
return LLVMErrorSuccess;
|
||||
} else
|
||||
return wrap(Handle.takeError());
|
||||
}
|
||||
|
||||
LLVMErrorRef LLVMOrcRemoveModule(LLVMOrcJITStackRef JITStack,
|
||||
LLVMOrcModuleHandle H) {
|
||||
OrcCBindingsStack &J = *unwrap(JITStack);
|
||||
return wrap(J.removeModule(H));
|
||||
}
|
||||
|
||||
LLVMErrorRef LLVMOrcGetSymbolAddress(LLVMOrcJITStackRef JITStack,
|
||||
LLVMOrcTargetAddress *RetAddr,
|
||||
const char *SymbolName) {
|
||||
OrcCBindingsStack &J = *unwrap(JITStack);
|
||||
if (auto Addr = J.findSymbolAddress(SymbolName, true)) {
|
||||
*RetAddr = *Addr;
|
||||
return LLVMErrorSuccess;
|
||||
} else
|
||||
return wrap(Addr.takeError());
|
||||
}
|
||||
|
||||
LLVMErrorRef LLVMOrcGetSymbolAddressIn(LLVMOrcJITStackRef JITStack,
|
||||
LLVMOrcTargetAddress *RetAddr,
|
||||
LLVMOrcModuleHandle H,
|
||||
const char *SymbolName) {
|
||||
OrcCBindingsStack &J = *unwrap(JITStack);
|
||||
if (auto Addr = J.findSymbolAddressIn(H, SymbolName, true)) {
|
||||
*RetAddr = *Addr;
|
||||
return LLVMErrorSuccess;
|
||||
} else
|
||||
return wrap(Addr.takeError());
|
||||
}
|
||||
|
||||
LLVMErrorRef LLVMOrcDisposeInstance(LLVMOrcJITStackRef JITStack) {
|
||||
auto *J = unwrap(JITStack);
|
||||
auto Err = J->shutdown();
|
||||
delete J;
|
||||
return wrap(std::move(Err));
|
||||
}
|
||||
|
||||
void LLVMOrcRegisterJITEventListener(LLVMOrcJITStackRef JITStack, LLVMJITEventListenerRef L)
|
||||
{
|
||||
unwrap(JITStack)->RegisterJITEventListener(unwrap(L));
|
||||
}
|
||||
|
||||
void LLVMOrcUnregisterJITEventListener(LLVMOrcJITStackRef JITStack, LLVMJITEventListenerRef L)
|
||||
{
|
||||
unwrap(JITStack)->UnregisterJITEventListener(unwrap(L));
|
||||
}
|
@ -1,534 +0,0 @@
|
||||
//===- OrcCBindingsStack.h - Orc JIT stack for C bindings -----*- C++ -*---===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_LIB_EXECUTIONENGINE_ORC_ORCCBINDINGSSTACK_H
|
||||
#define LLVM_LIB_EXECUTIONENGINE_ORC_ORCCBINDINGSSTACK_H
|
||||
|
||||
#include "llvm-c/OrcBindings.h"
|
||||
#include "llvm-c/TargetMachine.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/ExecutionEngine/JITSymbol.h"
|
||||
#include "llvm/ExecutionEngine/JITEventListener.h"
|
||||
#include "llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h"
|
||||
#include "llvm/ExecutionEngine/Orc/CompileUtils.h"
|
||||
#include "llvm/ExecutionEngine/Orc/ExecutionUtils.h"
|
||||
#include "llvm/ExecutionEngine/Orc/IRCompileLayer.h"
|
||||
#include "llvm/ExecutionEngine/Orc/LambdaResolver.h"
|
||||
#include "llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h"
|
||||
#include "llvm/ExecutionEngine/RuntimeDyld.h"
|
||||
#include "llvm/ExecutionEngine/SectionMemoryManager.h"
|
||||
#include "llvm/IR/DataLayout.h"
|
||||
#include "llvm/IR/Mangler.h"
|
||||
#include "llvm/IR/Module.h"
|
||||
#include "llvm/Support/CBindingWrapping.h"
|
||||
#include "llvm/Support/Error.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "llvm/Target/TargetMachine.h"
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class OrcCBindingsStack;
|
||||
|
||||
DEFINE_SIMPLE_CONVERSION_FUNCTIONS(OrcCBindingsStack, LLVMOrcJITStackRef)
|
||||
DEFINE_SIMPLE_CONVERSION_FUNCTIONS(TargetMachine, LLVMTargetMachineRef)
|
||||
|
||||
namespace detail {
|
||||
|
||||
// FIXME: Kill this off once the Layer concept becomes an interface.
|
||||
class GenericLayer {
|
||||
public:
|
||||
virtual ~GenericLayer() = default;
|
||||
|
||||
virtual JITSymbol findSymbolIn(orc::VModuleKey K, const std::string &Name,
|
||||
bool ExportedSymbolsOnly) = 0;
|
||||
virtual Error removeModule(orc::VModuleKey K) = 0;
|
||||
};
|
||||
|
||||
template <typename LayerT> class GenericLayerImpl : public GenericLayer {
|
||||
public:
|
||||
GenericLayerImpl(LayerT &Layer) : Layer(Layer) {}
|
||||
|
||||
JITSymbol findSymbolIn(orc::VModuleKey K, const std::string &Name,
|
||||
bool ExportedSymbolsOnly) override {
|
||||
return Layer.findSymbolIn(K, Name, ExportedSymbolsOnly);
|
||||
}
|
||||
|
||||
Error removeModule(orc::VModuleKey K) override {
|
||||
return Layer.removeModule(K);
|
||||
}
|
||||
|
||||
private:
|
||||
LayerT &Layer;
|
||||
};
|
||||
|
||||
template <>
|
||||
class GenericLayerImpl<orc::LegacyRTDyldObjectLinkingLayer> : public GenericLayer {
|
||||
private:
|
||||
using LayerT = orc::LegacyRTDyldObjectLinkingLayer;
|
||||
public:
|
||||
GenericLayerImpl(LayerT &Layer) : Layer(Layer) {}
|
||||
|
||||
JITSymbol findSymbolIn(orc::VModuleKey K, const std::string &Name,
|
||||
bool ExportedSymbolsOnly) override {
|
||||
return Layer.findSymbolIn(K, Name, ExportedSymbolsOnly);
|
||||
}
|
||||
|
||||
Error removeModule(orc::VModuleKey K) override {
|
||||
return Layer.removeObject(K);
|
||||
}
|
||||
|
||||
private:
|
||||
LayerT &Layer;
|
||||
};
|
||||
|
||||
template <typename LayerT>
|
||||
std::unique_ptr<GenericLayerImpl<LayerT>> createGenericLayer(LayerT &Layer) {
|
||||
return std::make_unique<GenericLayerImpl<LayerT>>(Layer);
|
||||
}
|
||||
|
||||
} // end namespace detail
|
||||
|
||||
class OrcCBindingsStack {
|
||||
public:
|
||||
|
||||
using CompileCallbackMgr = orc::JITCompileCallbackManager;
|
||||
using ObjLayerT = orc::LegacyRTDyldObjectLinkingLayer;
|
||||
using CompileLayerT = orc::LegacyIRCompileLayer<ObjLayerT, orc::SimpleCompiler>;
|
||||
using CODLayerT =
|
||||
orc::LegacyCompileOnDemandLayer<CompileLayerT, CompileCallbackMgr>;
|
||||
|
||||
using CallbackManagerBuilder =
|
||||
std::function<std::unique_ptr<CompileCallbackMgr>()>;
|
||||
|
||||
using IndirectStubsManagerBuilder = CODLayerT::IndirectStubsManagerBuilderT;
|
||||
|
||||
private:
|
||||
|
||||
using OwningObject = object::OwningBinary<object::ObjectFile>;
|
||||
|
||||
class CBindingsResolver : public orc::SymbolResolver {
|
||||
public:
|
||||
CBindingsResolver(OrcCBindingsStack &Stack,
|
||||
LLVMOrcSymbolResolverFn ExternalResolver,
|
||||
void *ExternalResolverCtx)
|
||||
: Stack(Stack), ExternalResolver(std::move(ExternalResolver)),
|
||||
ExternalResolverCtx(std::move(ExternalResolverCtx)) {}
|
||||
|
||||
orc::SymbolNameSet
|
||||
getResponsibilitySet(const orc::SymbolNameSet &Symbols) override {
|
||||
orc::SymbolNameSet Result;
|
||||
|
||||
for (auto &S : Symbols) {
|
||||
if (auto Sym = findSymbol(std::string(*S))) {
|
||||
if (!Sym.getFlags().isStrong())
|
||||
Result.insert(S);
|
||||
} else if (auto Err = Sym.takeError()) {
|
||||
Stack.reportError(std::move(Err));
|
||||
return orc::SymbolNameSet();
|
||||
}
|
||||
}
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
orc::SymbolNameSet
|
||||
lookup(std::shared_ptr<orc::AsynchronousSymbolQuery> Query,
|
||||
orc::SymbolNameSet Symbols) override {
|
||||
orc::SymbolNameSet UnresolvedSymbols;
|
||||
|
||||
for (auto &S : Symbols) {
|
||||
if (auto Sym = findSymbol(std::string(*S))) {
|
||||
if (auto Addr = Sym.getAddress()) {
|
||||
Query->notifySymbolMetRequiredState(
|
||||
S, JITEvaluatedSymbol(*Addr, Sym.getFlags()));
|
||||
} else {
|
||||
Stack.ES.legacyFailQuery(*Query, Addr.takeError());
|
||||
return orc::SymbolNameSet();
|
||||
}
|
||||
} else if (auto Err = Sym.takeError()) {
|
||||
Stack.ES.legacyFailQuery(*Query, std::move(Err));
|
||||
return orc::SymbolNameSet();
|
||||
} else
|
||||
UnresolvedSymbols.insert(S);
|
||||
}
|
||||
|
||||
if (Query->isComplete())
|
||||
Query->handleComplete();
|
||||
|
||||
return UnresolvedSymbols;
|
||||
}
|
||||
|
||||
private:
|
||||
JITSymbol findSymbol(const std::string &Name) {
|
||||
// Search order:
|
||||
// 1. JIT'd symbols.
|
||||
// 2. Runtime overrides.
|
||||
// 3. External resolver (if present).
|
||||
|
||||
if (Stack.CODLayer) {
|
||||
if (auto Sym = Stack.CODLayer->findSymbol(Name, true))
|
||||
return Sym;
|
||||
else if (auto Err = Sym.takeError())
|
||||
return Sym.takeError();
|
||||
} else {
|
||||
if (auto Sym = Stack.CompileLayer.findSymbol(Name, true))
|
||||
return Sym;
|
||||
else if (auto Err = Sym.takeError())
|
||||
return Sym.takeError();
|
||||
}
|
||||
|
||||
if (auto Sym = Stack.CXXRuntimeOverrides.searchOverrides(Name))
|
||||
return Sym;
|
||||
|
||||
if (ExternalResolver)
|
||||
return JITSymbol(ExternalResolver(Name.c_str(), ExternalResolverCtx),
|
||||
JITSymbolFlags::Exported);
|
||||
|
||||
return JITSymbol(nullptr);
|
||||
}
|
||||
|
||||
OrcCBindingsStack &Stack;
|
||||
LLVMOrcSymbolResolverFn ExternalResolver;
|
||||
void *ExternalResolverCtx = nullptr;
|
||||
};
|
||||
|
||||
public:
|
||||
OrcCBindingsStack(TargetMachine &TM,
|
||||
IndirectStubsManagerBuilder IndirectStubsMgrBuilder)
|
||||
: CCMgr(createCompileCallbackManager(TM, ES)), DL(TM.createDataLayout()),
|
||||
IndirectStubsMgr(IndirectStubsMgrBuilder()),
|
||||
ObjectLayer(
|
||||
AcknowledgeORCv1Deprecation, ES,
|
||||
[this](orc::VModuleKey K) {
|
||||
auto ResolverI = Resolvers.find(K);
|
||||
assert(ResolverI != Resolvers.end() &&
|
||||
"No resolver for module K");
|
||||
auto Resolver = std::move(ResolverI->second);
|
||||
Resolvers.erase(ResolverI);
|
||||
return ObjLayerT::Resources{
|
||||
std::make_shared<SectionMemoryManager>(), Resolver};
|
||||
},
|
||||
nullptr,
|
||||
[this](orc::VModuleKey K, const object::ObjectFile &Obj,
|
||||
const RuntimeDyld::LoadedObjectInfo &LoadedObjInfo) {
|
||||
this->notifyFinalized(K, Obj, LoadedObjInfo);
|
||||
},
|
||||
[this](orc::VModuleKey K, const object::ObjectFile &Obj) {
|
||||
this->notifyFreed(K, Obj);
|
||||
}),
|
||||
CompileLayer(AcknowledgeORCv1Deprecation, ObjectLayer,
|
||||
orc::SimpleCompiler(TM)),
|
||||
CODLayer(createCODLayer(ES, CompileLayer, CCMgr.get(),
|
||||
std::move(IndirectStubsMgrBuilder), Resolvers)),
|
||||
CXXRuntimeOverrides(
|
||||
AcknowledgeORCv1Deprecation,
|
||||
[this](const std::string &S) { return mangle(S); }) {}
|
||||
|
||||
Error shutdown() {
|
||||
// Run any destructors registered with __cxa_atexit.
|
||||
CXXRuntimeOverrides.runDestructors();
|
||||
// Run any IR destructors.
|
||||
for (auto &DtorRunner : IRStaticDestructorRunners)
|
||||
if (auto Err = DtorRunner.runViaLayer(*this))
|
||||
return Err;
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
std::string mangle(StringRef Name) {
|
||||
std::string MangledName;
|
||||
{
|
||||
raw_string_ostream MangledNameStream(MangledName);
|
||||
Mangler::getNameWithPrefix(MangledNameStream, Name, DL);
|
||||
}
|
||||
return MangledName;
|
||||
}
|
||||
|
||||
template <typename PtrTy>
|
||||
static PtrTy fromTargetAddress(JITTargetAddress Addr) {
|
||||
return reinterpret_cast<PtrTy>(static_cast<uintptr_t>(Addr));
|
||||
}
|
||||
|
||||
Expected<JITTargetAddress>
|
||||
createLazyCompileCallback(LLVMOrcLazyCompileCallbackFn Callback,
|
||||
void *CallbackCtx) {
|
||||
auto WrappedCallback = [=]() -> JITTargetAddress {
|
||||
return Callback(wrap(this), CallbackCtx);
|
||||
};
|
||||
|
||||
return CCMgr->getCompileCallback(std::move(WrappedCallback));
|
||||
}
|
||||
|
||||
Error createIndirectStub(StringRef StubName, JITTargetAddress Addr) {
|
||||
return IndirectStubsMgr->createStub(StubName, Addr,
|
||||
JITSymbolFlags::Exported);
|
||||
}
|
||||
|
||||
Error setIndirectStubPointer(StringRef Name, JITTargetAddress Addr) {
|
||||
return IndirectStubsMgr->updatePointer(Name, Addr);
|
||||
}
|
||||
|
||||
template <typename LayerT>
|
||||
Expected<orc::VModuleKey>
|
||||
addIRModule(LayerT &Layer, std::unique_ptr<Module> M,
|
||||
std::unique_ptr<RuntimeDyld::MemoryManager> MemMgr,
|
||||
LLVMOrcSymbolResolverFn ExternalResolver,
|
||||
void *ExternalResolverCtx) {
|
||||
|
||||
// Attach a data-layout if one isn't already present.
|
||||
if (M->getDataLayout().isDefault())
|
||||
M->setDataLayout(DL);
|
||||
|
||||
// Record the static constructors and destructors. We have to do this before
|
||||
// we hand over ownership of the module to the JIT.
|
||||
std::vector<std::string> CtorNames, DtorNames;
|
||||
for (auto Ctor : orc::getConstructors(*M))
|
||||
CtorNames.push_back(mangle(Ctor.Func->getName()));
|
||||
for (auto Dtor : orc::getDestructors(*M))
|
||||
DtorNames.push_back(mangle(Dtor.Func->getName()));
|
||||
|
||||
// Add the module to the JIT.
|
||||
auto K = ES.allocateVModule();
|
||||
Resolvers[K] = std::make_shared<CBindingsResolver>(*this, ExternalResolver,
|
||||
ExternalResolverCtx);
|
||||
if (auto Err = Layer.addModule(K, std::move(M)))
|
||||
return std::move(Err);
|
||||
|
||||
KeyLayers[K] = detail::createGenericLayer(Layer);
|
||||
|
||||
// Run the static constructors, and save the static destructor runner for
|
||||
// execution when the JIT is torn down.
|
||||
orc::LegacyCtorDtorRunner<OrcCBindingsStack> CtorRunner(
|
||||
AcknowledgeORCv1Deprecation, std::move(CtorNames), K);
|
||||
if (auto Err = CtorRunner.runViaLayer(*this))
|
||||
return std::move(Err);
|
||||
|
||||
IRStaticDestructorRunners.emplace_back(AcknowledgeORCv1Deprecation,
|
||||
std::move(DtorNames), K);
|
||||
|
||||
return K;
|
||||
}
|
||||
|
||||
Expected<orc::VModuleKey>
|
||||
addIRModuleEager(std::unique_ptr<Module> M,
|
||||
LLVMOrcSymbolResolverFn ExternalResolver,
|
||||
void *ExternalResolverCtx) {
|
||||
return addIRModule(CompileLayer, std::move(M),
|
||||
std::make_unique<SectionMemoryManager>(),
|
||||
std::move(ExternalResolver), ExternalResolverCtx);
|
||||
}
|
||||
|
||||
Expected<orc::VModuleKey>
|
||||
addIRModuleLazy(std::unique_ptr<Module> M,
|
||||
LLVMOrcSymbolResolverFn ExternalResolver,
|
||||
void *ExternalResolverCtx) {
|
||||
if (!CODLayer)
|
||||
return make_error<StringError>("Can not add lazy module: No compile "
|
||||
"callback manager available",
|
||||
inconvertibleErrorCode());
|
||||
|
||||
return addIRModule(*CODLayer, std::move(M),
|
||||
std::make_unique<SectionMemoryManager>(),
|
||||
std::move(ExternalResolver), ExternalResolverCtx);
|
||||
}
|
||||
|
||||
Error removeModule(orc::VModuleKey K) {
|
||||
// FIXME: Should error release the module key?
|
||||
if (auto Err = KeyLayers[K]->removeModule(K))
|
||||
return Err;
|
||||
ES.releaseVModule(K);
|
||||
KeyLayers.erase(K);
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Expected<orc::VModuleKey> addObject(std::unique_ptr<MemoryBuffer> ObjBuffer,
|
||||
LLVMOrcSymbolResolverFn ExternalResolver,
|
||||
void *ExternalResolverCtx) {
|
||||
if (auto Obj = object::ObjectFile::createObjectFile(
|
||||
ObjBuffer->getMemBufferRef())) {
|
||||
|
||||
auto K = ES.allocateVModule();
|
||||
Resolvers[K] = std::make_shared<CBindingsResolver>(
|
||||
*this, ExternalResolver, ExternalResolverCtx);
|
||||
|
||||
if (auto Err = ObjectLayer.addObject(K, std::move(ObjBuffer)))
|
||||
return std::move(Err);
|
||||
|
||||
KeyLayers[K] = detail::createGenericLayer(ObjectLayer);
|
||||
|
||||
return K;
|
||||
} else
|
||||
return Obj.takeError();
|
||||
}
|
||||
|
||||
JITSymbol findSymbol(const std::string &Name,
|
||||
bool ExportedSymbolsOnly) {
|
||||
if (auto Sym = IndirectStubsMgr->findStub(Name, ExportedSymbolsOnly))
|
||||
return Sym;
|
||||
if (CODLayer)
|
||||
return CODLayer->findSymbol(mangle(Name), ExportedSymbolsOnly);
|
||||
return CompileLayer.findSymbol(mangle(Name), ExportedSymbolsOnly);
|
||||
}
|
||||
|
||||
JITSymbol findSymbolIn(orc::VModuleKey K, const std::string &Name,
|
||||
bool ExportedSymbolsOnly) {
|
||||
assert(KeyLayers.count(K) && "looking up symbol in unknown module");
|
||||
return KeyLayers[K]->findSymbolIn(K, mangle(Name), ExportedSymbolsOnly);
|
||||
}
|
||||
|
||||
Expected<JITTargetAddress> findSymbolAddress(const std::string &Name,
|
||||
bool ExportedSymbolsOnly) {
|
||||
if (auto Sym = findSymbol(Name, ExportedSymbolsOnly)) {
|
||||
// Successful lookup, non-null symbol:
|
||||
if (auto AddrOrErr = Sym.getAddress())
|
||||
return *AddrOrErr;
|
||||
else
|
||||
return AddrOrErr.takeError();
|
||||
} else if (auto Err = Sym.takeError()) {
|
||||
// Lookup failure - report error.
|
||||
return std::move(Err);
|
||||
}
|
||||
|
||||
// No symbol not found. Return 0.
|
||||
return 0;
|
||||
}
|
||||
|
||||
Expected<JITTargetAddress> findSymbolAddressIn(orc::VModuleKey K,
|
||||
const std::string &Name,
|
||||
bool ExportedSymbolsOnly) {
|
||||
if (auto Sym = findSymbolIn(K, Name, ExportedSymbolsOnly)) {
|
||||
// Successful lookup, non-null symbol:
|
||||
if (auto AddrOrErr = Sym.getAddress())
|
||||
return *AddrOrErr;
|
||||
else
|
||||
return AddrOrErr.takeError();
|
||||
} else if (auto Err = Sym.takeError()) {
|
||||
// Lookup failure - report error.
|
||||
return std::move(Err);
|
||||
}
|
||||
|
||||
// Symbol not found. Return 0.
|
||||
return 0;
|
||||
}
|
||||
|
||||
const std::string &getErrorMessage() const { return ErrMsg; }
|
||||
|
||||
void RegisterJITEventListener(JITEventListener *L) {
|
||||
if (!L)
|
||||
return;
|
||||
EventListeners.push_back(L);
|
||||
}
|
||||
|
||||
void UnregisterJITEventListener(JITEventListener *L) {
|
||||
if (!L)
|
||||
return;
|
||||
|
||||
auto I = find(reverse(EventListeners), L);
|
||||
if (I != EventListeners.rend()) {
|
||||
std::swap(*I, EventListeners.back());
|
||||
EventListeners.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
using ResolverMap =
|
||||
std::map<orc::VModuleKey, std::shared_ptr<orc::SymbolResolver>>;
|
||||
|
||||
static std::unique_ptr<CompileCallbackMgr>
|
||||
createCompileCallbackManager(TargetMachine &TM, orc::ExecutionSession &ES) {
|
||||
auto CCMgr = createLocalCompileCallbackManager(TM.getTargetTriple(), ES, 0);
|
||||
if (!CCMgr) {
|
||||
// FIXME: It would be good if we could report this somewhere, but we do
|
||||
// have an instance yet.
|
||||
logAllUnhandledErrors(CCMgr.takeError(), errs(), "ORC error: ");
|
||||
return nullptr;
|
||||
}
|
||||
return std::move(*CCMgr);
|
||||
}
|
||||
|
||||
static std::unique_ptr<CODLayerT>
|
||||
createCODLayer(orc::ExecutionSession &ES, CompileLayerT &CompileLayer,
|
||||
CompileCallbackMgr *CCMgr,
|
||||
IndirectStubsManagerBuilder IndirectStubsMgrBuilder,
|
||||
ResolverMap &Resolvers) {
|
||||
// If there is no compile callback manager available we can not create a
|
||||
// compile on demand layer.
|
||||
if (!CCMgr)
|
||||
return nullptr;
|
||||
|
||||
return std::make_unique<CODLayerT>(
|
||||
AcknowledgeORCv1Deprecation, ES, CompileLayer,
|
||||
[&Resolvers](orc::VModuleKey K) {
|
||||
auto ResolverI = Resolvers.find(K);
|
||||
assert(ResolverI != Resolvers.end() && "No resolver for module K");
|
||||
return ResolverI->second;
|
||||
},
|
||||
[&Resolvers](orc::VModuleKey K,
|
||||
std::shared_ptr<orc::SymbolResolver> Resolver) {
|
||||
assert(!Resolvers.count(K) && "Resolver already present");
|
||||
Resolvers[K] = std::move(Resolver);
|
||||
},
|
||||
[](Function &F) { return std::set<Function *>({&F}); }, *CCMgr,
|
||||
std::move(IndirectStubsMgrBuilder), false);
|
||||
}
|
||||
|
||||
void reportError(Error Err) {
|
||||
// FIXME: Report errors on the execution session.
|
||||
logAllUnhandledErrors(std::move(Err), errs(), "ORC error: ");
|
||||
};
|
||||
|
||||
void notifyFinalized(orc::VModuleKey K,
|
||||
const object::ObjectFile &Obj,
|
||||
const RuntimeDyld::LoadedObjectInfo &LoadedObjInfo) {
|
||||
uint64_t Key = static_cast<uint64_t>(
|
||||
reinterpret_cast<uintptr_t>(Obj.getData().data()));
|
||||
for (auto &Listener : EventListeners)
|
||||
Listener->notifyObjectLoaded(Key, Obj, LoadedObjInfo);
|
||||
}
|
||||
|
||||
void notifyFreed(orc::VModuleKey K, const object::ObjectFile &Obj) {
|
||||
uint64_t Key = static_cast<uint64_t>(
|
||||
reinterpret_cast<uintptr_t>(Obj.getData().data()));
|
||||
for (auto &Listener : EventListeners)
|
||||
Listener->notifyFreeingObject(Key);
|
||||
}
|
||||
|
||||
orc::ExecutionSession ES;
|
||||
std::unique_ptr<CompileCallbackMgr> CCMgr;
|
||||
|
||||
std::vector<JITEventListener *> EventListeners;
|
||||
|
||||
DataLayout DL;
|
||||
SectionMemoryManager CCMgrMemMgr;
|
||||
|
||||
std::unique_ptr<orc::IndirectStubsManager> IndirectStubsMgr;
|
||||
|
||||
ObjLayerT ObjectLayer;
|
||||
CompileLayerT CompileLayer;
|
||||
std::unique_ptr<CODLayerT> CODLayer;
|
||||
|
||||
std::map<orc::VModuleKey, std::unique_ptr<detail::GenericLayer>> KeyLayers;
|
||||
|
||||
orc::LegacyLocalCXXRuntimeOverrides CXXRuntimeOverrides;
|
||||
std::vector<orc::LegacyCtorDtorRunner<OrcCBindingsStack>> IRStaticDestructorRunners;
|
||||
std::string ErrMsg;
|
||||
|
||||
ResolverMap Resolvers;
|
||||
};
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_LIB_EXECUTIONENGINE_ORC_ORCCBINDINGSSTACK_H
|
@ -1,138 +0,0 @@
|
||||
//===-------- OrcMCJITReplacement.cpp - Orc-based MCJIT replacement -------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#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,
|
||||
ArrayRef<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!");
|
||||
}
|
||||
|
||||
void OrcMCJITReplacement::runStaticConstructorsDestructors(bool isDtors) {
|
||||
auto &CtorDtorsMap = isDtors ? UnexecutedDestructors : UnexecutedConstructors;
|
||||
|
||||
for (auto &KV : CtorDtorsMap)
|
||||
cantFail(LegacyCtorDtorRunner<LazyEmitLayerT>(
|
||||
AcknowledgeORCv1Deprecation, std::move(KV.second), KV.first)
|
||||
.runViaLayer(LazyEmitLayer));
|
||||
|
||||
CtorDtorsMap.clear();
|
||||
}
|
||||
|
||||
} // End namespace orc.
|
||||
} // End namespace llvm.
|
@ -1,502 +0,0 @@
|
||||
//===- OrcMCJITReplacement.h - Orc based MCJIT replacement ------*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Orc based MCJIT replacement.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_LIB_EXECUTIONENGINE_ORC_ORCMCJITREPLACEMENT_H
|
||||
#define LLVM_LIB_EXECUTIONENGINE_ORC_ORCMCJITREPLACEMENT_H
|
||||
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/ExecutionEngine/ExecutionEngine.h"
|
||||
#include "llvm/ExecutionEngine/GenericValue.h"
|
||||
#include "llvm/ExecutionEngine/JITSymbol.h"
|
||||
#include "llvm/ExecutionEngine/Orc/CompileUtils.h"
|
||||
#include "llvm/ExecutionEngine/Orc/ExecutionUtils.h"
|
||||
#include "llvm/ExecutionEngine/Orc/IRCompileLayer.h"
|
||||
#include "llvm/ExecutionEngine/Orc/LazyEmittingLayer.h"
|
||||
#include "llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h"
|
||||
#include "llvm/ExecutionEngine/RTDyldMemoryManager.h"
|
||||
#include "llvm/ExecutionEngine/RuntimeDyld.h"
|
||||
#include "llvm/IR/DataLayout.h"
|
||||
#include "llvm/IR/Function.h"
|
||||
#include "llvm/IR/Mangler.h"
|
||||
#include "llvm/IR/Module.h"
|
||||
#include "llvm/Object/Archive.h"
|
||||
#include "llvm/Object/Binary.h"
|
||||
#include "llvm/Object/ObjectFile.h"
|
||||
#include "llvm/Support/Error.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "llvm/Target/TargetMachine.h"
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class ObjectCache;
|
||||
|
||||
namespace orc {
|
||||
|
||||
class OrcMCJITReplacement : public ExecutionEngine {
|
||||
|
||||
// OrcMCJITReplacement needs to do a little extra book-keeping to ensure that
|
||||
// Orc's automatic finalization doesn't kick in earlier than MCJIT clients are
|
||||
// expecting - see finalizeMemory.
|
||||
class MCJITReplacementMemMgr : public MCJITMemoryManager {
|
||||
public:
|
||||
MCJITReplacementMemMgr(OrcMCJITReplacement &M,
|
||||
std::shared_ptr<MCJITMemoryManager> ClientMM)
|
||||
: M(M), ClientMM(std::move(ClientMM)) {}
|
||||
|
||||
uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment,
|
||||
unsigned SectionID,
|
||||
StringRef SectionName) override {
|
||||
uint8_t *Addr =
|
||||
ClientMM->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 = ClientMM->allocateDataSection(Size, Alignment, SectionID,
|
||||
SectionName, IsReadOnly);
|
||||
M.SectionsAllocatedSinceLastLoad.insert(Addr);
|
||||
return Addr;
|
||||
}
|
||||
|
||||
void reserveAllocationSpace(uintptr_t CodeSize, uint32_t CodeAlign,
|
||||
uintptr_t RODataSize, uint32_t RODataAlign,
|
||||
uintptr_t RWDataSize,
|
||||
uint32_t RWDataAlign) override {
|
||||
return ClientMM->reserveAllocationSpace(CodeSize, CodeAlign,
|
||||
RODataSize, RODataAlign,
|
||||
RWDataSize, RWDataAlign);
|
||||
}
|
||||
|
||||
bool needsToReserveAllocationSpace() override {
|
||||
return ClientMM->needsToReserveAllocationSpace();
|
||||
}
|
||||
|
||||
void registerEHFrames(uint8_t *Addr, uint64_t LoadAddr,
|
||||
size_t Size) override {
|
||||
return ClientMM->registerEHFrames(Addr, LoadAddr, Size);
|
||||
}
|
||||
|
||||
void deregisterEHFrames() override {
|
||||
return ClientMM->deregisterEHFrames();
|
||||
}
|
||||
|
||||
void notifyObjectLoaded(RuntimeDyld &RTDyld,
|
||||
const object::ObjectFile &O) override {
|
||||
return ClientMM->notifyObjectLoaded(RTDyld, O);
|
||||
}
|
||||
|
||||
void notifyObjectLoaded(ExecutionEngine *EE,
|
||||
const object::ObjectFile &O) override {
|
||||
return ClientMM->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 ClientMM->finalizeMemory(ErrMsg);
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
OrcMCJITReplacement &M;
|
||||
std::shared_ptr<MCJITMemoryManager> ClientMM;
|
||||
};
|
||||
|
||||
class LinkingORCResolver : public orc::SymbolResolver {
|
||||
public:
|
||||
LinkingORCResolver(OrcMCJITReplacement &M) : M(M) {}
|
||||
|
||||
SymbolNameSet getResponsibilitySet(const SymbolNameSet &Symbols) override {
|
||||
SymbolNameSet Result;
|
||||
|
||||
for (auto &S : Symbols) {
|
||||
if (auto Sym = M.findMangledSymbol(*S)) {
|
||||
if (!Sym.getFlags().isStrong())
|
||||
Result.insert(S);
|
||||
} else if (auto Err = Sym.takeError()) {
|
||||
M.reportError(std::move(Err));
|
||||
return SymbolNameSet();
|
||||
} else {
|
||||
if (auto Sym2 =
|
||||
M.ClientResolver->findSymbolInLogicalDylib(std::string(*S))) {
|
||||
if (!Sym2.getFlags().isStrong())
|
||||
Result.insert(S);
|
||||
} else if (auto Err = Sym2.takeError()) {
|
||||
M.reportError(std::move(Err));
|
||||
return SymbolNameSet();
|
||||
} else
|
||||
Result.insert(S);
|
||||
}
|
||||
}
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
SymbolNameSet lookup(std::shared_ptr<AsynchronousSymbolQuery> Query,
|
||||
SymbolNameSet Symbols) override {
|
||||
SymbolNameSet UnresolvedSymbols;
|
||||
bool NewSymbolsResolved = false;
|
||||
|
||||
for (auto &S : Symbols) {
|
||||
if (auto Sym = M.findMangledSymbol(*S)) {
|
||||
if (auto Addr = Sym.getAddress()) {
|
||||
Query->notifySymbolMetRequiredState(
|
||||
S, JITEvaluatedSymbol(*Addr, Sym.getFlags()));
|
||||
NewSymbolsResolved = true;
|
||||
} else {
|
||||
M.ES.legacyFailQuery(*Query, Addr.takeError());
|
||||
return SymbolNameSet();
|
||||
}
|
||||
} else if (auto Err = Sym.takeError()) {
|
||||
M.ES.legacyFailQuery(*Query, std::move(Err));
|
||||
return SymbolNameSet();
|
||||
} else {
|
||||
if (auto Sym2 = M.ClientResolver->findSymbol(std::string(*S))) {
|
||||
if (auto Addr = Sym2.getAddress()) {
|
||||
Query->notifySymbolMetRequiredState(
|
||||
S, JITEvaluatedSymbol(*Addr, Sym2.getFlags()));
|
||||
NewSymbolsResolved = true;
|
||||
} else {
|
||||
M.ES.legacyFailQuery(*Query, Addr.takeError());
|
||||
return SymbolNameSet();
|
||||
}
|
||||
} else if (auto Err = Sym2.takeError()) {
|
||||
M.ES.legacyFailQuery(*Query, std::move(Err));
|
||||
return SymbolNameSet();
|
||||
} else
|
||||
UnresolvedSymbols.insert(S);
|
||||
}
|
||||
}
|
||||
|
||||
if (NewSymbolsResolved && Query->isComplete())
|
||||
Query->handleComplete();
|
||||
|
||||
return UnresolvedSymbols;
|
||||
}
|
||||
|
||||
private:
|
||||
OrcMCJITReplacement &M;
|
||||
};
|
||||
|
||||
private:
|
||||
static ExecutionEngine *
|
||||
createOrcMCJITReplacement(std::string *ErrorMsg,
|
||||
std::shared_ptr<MCJITMemoryManager> MemMgr,
|
||||
std::shared_ptr<LegacyJITSymbolResolver> Resolver,
|
||||
std::unique_ptr<TargetMachine> TM) {
|
||||
return new OrcMCJITReplacement(std::move(MemMgr), std::move(Resolver),
|
||||
std::move(TM));
|
||||
}
|
||||
|
||||
void reportError(Error Err) {
|
||||
logAllUnhandledErrors(std::move(Err), errs(), "MCJIT error: ");
|
||||
}
|
||||
|
||||
public:
|
||||
OrcMCJITReplacement(std::shared_ptr<MCJITMemoryManager> MemMgr,
|
||||
std::shared_ptr<LegacyJITSymbolResolver> ClientResolver,
|
||||
std::unique_ptr<TargetMachine> TM)
|
||||
: ExecutionEngine(TM->createDataLayout()), TM(std::move(TM)),
|
||||
MemMgr(
|
||||
std::make_shared<MCJITReplacementMemMgr>(*this, std::move(MemMgr))),
|
||||
Resolver(std::make_shared<LinkingORCResolver>(*this)),
|
||||
ClientResolver(std::move(ClientResolver)), NotifyObjectLoaded(*this),
|
||||
NotifyFinalized(*this),
|
||||
ObjectLayer(
|
||||
AcknowledgeORCv1Deprecation, ES,
|
||||
[this](VModuleKey K) {
|
||||
return ObjectLayerT::Resources{this->MemMgr, this->Resolver};
|
||||
},
|
||||
NotifyObjectLoaded, NotifyFinalized),
|
||||
CompileLayer(AcknowledgeORCv1Deprecation, ObjectLayer,
|
||||
SimpleCompiler(*this->TM),
|
||||
[this](VModuleKey K, std::unique_ptr<Module> M) {
|
||||
Modules.push_back(std::move(M));
|
||||
}),
|
||||
LazyEmitLayer(AcknowledgeORCv1Deprecation, CompileLayer) {}
|
||||
|
||||
static void Register() {
|
||||
OrcMCJITReplacementCtor = createOrcMCJITReplacement;
|
||||
}
|
||||
|
||||
void addModule(std::unique_ptr<Module> M) override {
|
||||
// If this module doesn't have a DataLayout attached then attach the
|
||||
// default.
|
||||
if (M->getDataLayout().isDefault()) {
|
||||
M->setDataLayout(getDataLayout());
|
||||
} else {
|
||||
assert(M->getDataLayout() == getDataLayout() && "DataLayout Mismatch");
|
||||
}
|
||||
|
||||
// Rename, bump linkage and record static constructors and destructors.
|
||||
// We have to do this before we hand over ownership of the module to the
|
||||
// JIT.
|
||||
std::vector<std::string> CtorNames, DtorNames;
|
||||
{
|
||||
unsigned CtorId = 0, DtorId = 0;
|
||||
for (auto Ctor : orc::getConstructors(*M)) {
|
||||
std::string NewCtorName = ("__ORCstatic_ctor." + Twine(CtorId++)).str();
|
||||
Ctor.Func->setName(NewCtorName);
|
||||
Ctor.Func->setLinkage(GlobalValue::ExternalLinkage);
|
||||
Ctor.Func->setVisibility(GlobalValue::HiddenVisibility);
|
||||
CtorNames.push_back(mangle(NewCtorName));
|
||||
}
|
||||
for (auto Dtor : orc::getDestructors(*M)) {
|
||||
std::string NewDtorName = ("__ORCstatic_dtor." + Twine(DtorId++)).str();
|
||||
dbgs() << "Found dtor: " << NewDtorName << "\n";
|
||||
Dtor.Func->setName(NewDtorName);
|
||||
Dtor.Func->setLinkage(GlobalValue::ExternalLinkage);
|
||||
Dtor.Func->setVisibility(GlobalValue::HiddenVisibility);
|
||||
DtorNames.push_back(mangle(NewDtorName));
|
||||
}
|
||||
}
|
||||
|
||||
auto K = ES.allocateVModule();
|
||||
|
||||
UnexecutedConstructors[K] = std::move(CtorNames);
|
||||
UnexecutedDestructors[K] = std::move(DtorNames);
|
||||
|
||||
cantFail(LazyEmitLayer.addModule(K, std::move(M)));
|
||||
}
|
||||
|
||||
void addObjectFile(std::unique_ptr<object::ObjectFile> O) override {
|
||||
cantFail(ObjectLayer.addObject(
|
||||
ES.allocateVModule(), MemoryBuffer::getMemBufferCopy(O->getData())));
|
||||
}
|
||||
|
||||
void addObjectFile(object::OwningBinary<object::ObjectFile> O) override {
|
||||
std::unique_ptr<object::ObjectFile> Obj;
|
||||
std::unique_ptr<MemoryBuffer> ObjBuffer;
|
||||
std::tie(Obj, ObjBuffer) = O.takeBinary();
|
||||
cantFail(ObjectLayer.addObject(ES.allocateVModule(), std::move(ObjBuffer)));
|
||||
}
|
||||
|
||||
void addArchive(object::OwningBinary<object::Archive> A) override {
|
||||
Archives.push_back(std::move(A));
|
||||
}
|
||||
|
||||
bool removeModule(Module *M) override {
|
||||
auto I = Modules.begin();
|
||||
for (auto E = Modules.end(); I != E; ++I)
|
||||
if (I->get() == M)
|
||||
break;
|
||||
if (I == Modules.end())
|
||||
return false;
|
||||
Modules.erase(I);
|
||||
return true;
|
||||
}
|
||||
|
||||
uint64_t getSymbolAddress(StringRef Name) {
|
||||
return cantFail(findSymbol(Name).getAddress());
|
||||
}
|
||||
|
||||
JITSymbol findSymbol(StringRef Name) {
|
||||
return findMangledSymbol(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,
|
||||
ArrayRef<GenericValue> ArgValues) override;
|
||||
|
||||
void setObjectCache(ObjectCache *NewCache) override {
|
||||
CompileLayer.getCompiler().setObjectCache(NewCache);
|
||||
}
|
||||
|
||||
void setProcessAllSections(bool ProcessAllSections) override {
|
||||
ObjectLayer.setProcessAllSections(ProcessAllSections);
|
||||
}
|
||||
|
||||
void runStaticConstructorsDestructors(bool isDtors) override;
|
||||
|
||||
private:
|
||||
JITSymbol findMangledSymbol(StringRef Name) {
|
||||
if (auto Sym = LazyEmitLayer.findSymbol(std::string(Name), false))
|
||||
return Sym;
|
||||
if (auto Sym = ClientResolver->findSymbol(std::string(Name)))
|
||||
return Sym;
|
||||
if (auto Sym = scanArchives(Name))
|
||||
return Sym;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
JITSymbol scanArchives(StringRef Name) {
|
||||
for (object::OwningBinary<object::Archive> &OB : Archives) {
|
||||
object::Archive *A = OB.getBinary();
|
||||
// Look for our symbols in each Archive
|
||||
auto OptionalChildOrErr = A->findSym(Name);
|
||||
if (!OptionalChildOrErr)
|
||||
report_fatal_error(OptionalChildOrErr.takeError());
|
||||
auto &OptionalChild = *OptionalChildOrErr;
|
||||
if (OptionalChild) {
|
||||
// FIXME: Support nested archives?
|
||||
Expected<std::unique_ptr<object::Binary>> ChildBinOrErr =
|
||||
OptionalChild->getAsBinary();
|
||||
if (!ChildBinOrErr) {
|
||||
// TODO: Actually report errors helpfully.
|
||||
consumeError(ChildBinOrErr.takeError());
|
||||
continue;
|
||||
}
|
||||
std::unique_ptr<object::Binary> &ChildBin = ChildBinOrErr.get();
|
||||
if (ChildBin->isObject()) {
|
||||
cantFail(ObjectLayer.addObject(
|
||||
ES.allocateVModule(),
|
||||
MemoryBuffer::getMemBufferCopy(ChildBin->getData())));
|
||||
if (auto Sym = ObjectLayer.findSymbol(Name, true))
|
||||
return Sym;
|
||||
}
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
class NotifyObjectLoadedT {
|
||||
public:
|
||||
using LoadedObjInfoListT =
|
||||
std::vector<std::unique_ptr<RuntimeDyld::LoadedObjectInfo>>;
|
||||
|
||||
NotifyObjectLoadedT(OrcMCJITReplacement &M) : M(M) {}
|
||||
|
||||
void operator()(VModuleKey K, const object::ObjectFile &Obj,
|
||||
const RuntimeDyld::LoadedObjectInfo &Info) const {
|
||||
M.UnfinalizedSections[K] = std::move(M.SectionsAllocatedSinceLastLoad);
|
||||
M.SectionsAllocatedSinceLastLoad = SectionAddrSet();
|
||||
M.MemMgr->notifyObjectLoaded(&M, Obj);
|
||||
}
|
||||
private:
|
||||
OrcMCJITReplacement &M;
|
||||
};
|
||||
|
||||
class NotifyFinalizedT {
|
||||
public:
|
||||
NotifyFinalizedT(OrcMCJITReplacement &M) : M(M) {}
|
||||
|
||||
void operator()(VModuleKey K, const object::ObjectFile &Obj,
|
||||
const RuntimeDyld::LoadedObjectInfo &Info) {
|
||||
M.UnfinalizedSections.erase(K);
|
||||
}
|
||||
|
||||
private:
|
||||
OrcMCJITReplacement &M;
|
||||
};
|
||||
|
||||
std::string mangle(StringRef Name) {
|
||||
std::string MangledName;
|
||||
{
|
||||
raw_string_ostream MangledNameStream(MangledName);
|
||||
Mang.getNameWithPrefix(MangledNameStream, Name, getDataLayout());
|
||||
}
|
||||
return MangledName;
|
||||
}
|
||||
|
||||
using ObjectLayerT = LegacyRTDyldObjectLinkingLayer;
|
||||
using CompileLayerT = LegacyIRCompileLayer<ObjectLayerT, orc::SimpleCompiler>;
|
||||
using LazyEmitLayerT = LazyEmittingLayer<CompileLayerT>;
|
||||
|
||||
ExecutionSession ES;
|
||||
|
||||
std::unique_ptr<TargetMachine> TM;
|
||||
std::shared_ptr<MCJITReplacementMemMgr> MemMgr;
|
||||
std::shared_ptr<LinkingORCResolver> Resolver;
|
||||
std::shared_ptr<LegacyJITSymbolResolver> ClientResolver;
|
||||
Mangler Mang;
|
||||
|
||||
// IMPORTANT: ShouldDelete *must* come before LocalModules: The shared_ptr
|
||||
// delete blocks in LocalModules refer to the ShouldDelete map, so
|
||||
// LocalModules needs to be destructed before ShouldDelete.
|
||||
std::map<Module*, bool> ShouldDelete;
|
||||
|
||||
NotifyObjectLoadedT NotifyObjectLoaded;
|
||||
NotifyFinalizedT NotifyFinalized;
|
||||
|
||||
ObjectLayerT ObjectLayer;
|
||||
CompileLayerT CompileLayer;
|
||||
LazyEmitLayerT LazyEmitLayer;
|
||||
|
||||
std::map<VModuleKey, std::vector<std::string>> UnexecutedConstructors;
|
||||
std::map<VModuleKey, std::vector<std::string>> UnexecutedDestructors;
|
||||
|
||||
// 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.
|
||||
using SectionAddrSet = std::set<const void *>;
|
||||
SectionAddrSet SectionsAllocatedSinceLastLoad;
|
||||
std::map<VModuleKey, SectionAddrSet> UnfinalizedSections;
|
||||
|
||||
std::vector<object::OwningBinary<object::Archive>> Archives;
|
||||
};
|
||||
|
||||
} // end namespace orc
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_LIB_EXECUTIONENGINE_ORC_MCJITREPLACEMENT_H
|
@ -318,14 +318,5 @@ void RTDyldObjectLinkingLayer::onObjEmit(
|
||||
NotifyEmitted(K, std::move(ObjBuffer));
|
||||
}
|
||||
|
||||
LegacyRTDyldObjectLinkingLayer::LegacyRTDyldObjectLinkingLayer(
|
||||
ExecutionSession &ES, ResourcesGetter GetResources,
|
||||
NotifyLoadedFtor NotifyLoaded, NotifyFinalizedFtor NotifyFinalized,
|
||||
NotifyFreedFtor NotifyFreed)
|
||||
: ES(ES), GetResources(std::move(GetResources)),
|
||||
NotifyLoaded(std::move(NotifyLoaded)),
|
||||
NotifyFinalized(std::move(NotifyFinalized)),
|
||||
NotifyFreed(std::move(NotifyFreed)), ProcessAllSections(false) {}
|
||||
|
||||
} // End namespace orc.
|
||||
} // End namespace llvm.
|
||||
|
@ -1,37 +0,0 @@
|
||||
; RUN: %lli -jit-kind=orc-mcjit %s > /dev/null
|
||||
|
||||
@.LC0 = internal global [10 x i8] c"argc: %d\0A\00" ; <[10 x i8]*> [#uses=1]
|
||||
|
||||
declare i32 @puts(i8*)
|
||||
|
||||
define void @getoptions(i32* %argc) {
|
||||
bb0:
|
||||
ret void
|
||||
}
|
||||
|
||||
declare i32 @printf(i8*, ...)
|
||||
|
||||
define i32 @main(i32 %argc, i8** %argv) {
|
||||
bb0:
|
||||
call i32 (i8*, ...) @printf( i8* getelementptr ([10 x i8], [10 x i8]* @.LC0, i64 0, i64 0), i32 %argc ) ; <i32>:0 [#uses=0]
|
||||
%cast224 = bitcast i8** %argv to i8* ; <i8*> [#uses=1]
|
||||
%local = alloca i8* ; <i8**> [#uses=3]
|
||||
store i8* %cast224, i8** %local
|
||||
%cond226 = icmp sle i32 %argc, 0 ; <i1> [#uses=1]
|
||||
br i1 %cond226, label %bb3, label %bb2
|
||||
bb2: ; preds = %bb2, %bb0
|
||||
%cann-indvar = phi i32 [ 0, %bb0 ], [ %add1-indvar, %bb2 ] ; <i32> [#uses=2]
|
||||
%add1-indvar = add i32 %cann-indvar, 1 ; <i32> [#uses=2]
|
||||
%cann-indvar-idxcast = sext i32 %cann-indvar to i64 ; <i64> [#uses=1]
|
||||
%CT = bitcast i8** %local to i8*** ; <i8***> [#uses=1]
|
||||
%reg115 = load i8**, i8*** %CT ; <i8**> [#uses=1]
|
||||
%cast235 = getelementptr i8*, i8** %reg115, i64 %cann-indvar-idxcast ; <i8**> [#uses=1]
|
||||
%reg117 = load i8*, i8** %cast235 ; <i8*> [#uses=1]
|
||||
%reg236 = call i32 @puts( i8* %reg117 ) ; <i32> [#uses=0]
|
||||
%cond239 = icmp slt i32 %add1-indvar, %argc ; <i1> [#uses=1]
|
||||
br i1 %cond239, label %bb2, label %bb3
|
||||
bb3: ; preds = %bb2, %bb0
|
||||
%cast243 = bitcast i8** %local to i32* ; <i32*> [#uses=1]
|
||||
call void @getoptions( i32* %cast243 )
|
||||
ret i32 0
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
; RUN: %lli -jit-kind=orc-mcjit %s > /dev/null
|
||||
|
||||
define i32 @foo(i32 %X, i32 %Y, double %A) {
|
||||
%cond212 = fcmp une double %A, 1.000000e+00 ; <i1> [#uses=1]
|
||||
%cast110 = zext i1 %cond212 to i32 ; <i32> [#uses=1]
|
||||
ret i32 %cast110
|
||||
}
|
||||
|
||||
define i32 @main() {
|
||||
%reg212 = call i32 @foo( i32 0, i32 1, double 1.000000e+00 ) ; <i32> [#uses=1]
|
||||
ret i32 %reg212
|
||||
}
|
||||
|
@ -1,20 +0,0 @@
|
||||
; RUN: %lli -jit-kind=orc-mcjit %s > /dev/null
|
||||
|
||||
define i32 @main() {
|
||||
call i32 @mylog( i32 4 ) ; <i32>:1 [#uses=0]
|
||||
ret i32 0
|
||||
}
|
||||
|
||||
define internal i32 @mylog(i32 %num) {
|
||||
bb0:
|
||||
br label %bb2
|
||||
bb2: ; preds = %bb2, %bb0
|
||||
%reg112 = phi i32 [ 10, %bb2 ], [ 1, %bb0 ] ; <i32> [#uses=1]
|
||||
%cann-indvar = phi i32 [ %cann-indvar, %bb2 ], [ 0, %bb0 ] ; <i32> [#uses=1]
|
||||
%reg114 = add i32 %reg112, 1 ; <i32> [#uses=2]
|
||||
%cond222 = icmp slt i32 %reg114, %num ; <i1> [#uses=1]
|
||||
br i1 %cond222, label %bb2, label %bb3
|
||||
bb3: ; preds = %bb2
|
||||
ret i32 %reg114
|
||||
}
|
||||
|
@ -1,12 +0,0 @@
|
||||
; RUN: %lli -jit-kind=orc-mcjit %s > /dev/null
|
||||
|
||||
define i32 @main() {
|
||||
; <label>:0
|
||||
br label %Loop
|
||||
Loop: ; preds = %Loop, %0
|
||||
%X = phi i32 [ 0, %0 ], [ 1, %Loop ] ; <i32> [#uses=1]
|
||||
br i1 true, label %Out, label %Loop
|
||||
Out: ; preds = %Loop
|
||||
ret i32 %X
|
||||
}
|
||||
|
@ -1,11 +0,0 @@
|
||||
; RUN: %lli -jit-kind=orc-mcjit %s > /dev/null
|
||||
|
||||
; We were accidentally inverting the signedness of right shifts. Whoops.
|
||||
|
||||
define i32 @main() {
|
||||
%X = ashr i32 -1, 16 ; <i32> [#uses=1]
|
||||
%Y = ashr i32 %X, 16 ; <i32> [#uses=1]
|
||||
%Z = add i32 %Y, 1 ; <i32> [#uses=1]
|
||||
ret i32 %Z
|
||||
}
|
||||
|
@ -1,10 +0,0 @@
|
||||
; RUN: %lli -jit-kind=orc-mcjit %s > /dev/null
|
||||
|
||||
define i32 @main() {
|
||||
%X = fadd double 0.000000e+00, 1.000000e+00 ; <double> [#uses=1]
|
||||
%Y = fsub double 0.000000e+00, 1.000000e+00 ; <double> [#uses=2]
|
||||
%Z = fcmp oeq double %X, %Y ; <i1> [#uses=0]
|
||||
fadd double %Y, 0.000000e+00 ; <double>:1 [#uses=0]
|
||||
ret i32 0
|
||||
}
|
||||
|
@ -1,17 +0,0 @@
|
||||
; RUN: %lli -jit-kind=orc-mcjit %s > /dev/null
|
||||
|
||||
define i32 @bar(i8* %X) {
|
||||
; pointer should be 4 byte aligned!
|
||||
%P = alloca double ; <double*> [#uses=1]
|
||||
%R = ptrtoint double* %P to i32 ; <i32> [#uses=1]
|
||||
%A = and i32 %R, 3 ; <i32> [#uses=1]
|
||||
ret i32 %A
|
||||
}
|
||||
|
||||
define i32 @main() {
|
||||
%SP = alloca i8 ; <i8*> [#uses=1]
|
||||
%X = add i32 0, 0 ; <i32> [#uses=1]
|
||||
alloca i8, i32 %X ; <i8*>:1 [#uses=0]
|
||||
call i32 @bar( i8* %SP ) ; <i32>:2 [#uses=1]
|
||||
ret i32 %2
|
||||
}
|
@ -1,19 +0,0 @@
|
||||
; This testcase should return with an exit code of 1.
|
||||
;
|
||||
; RUN: not %lli -jit-kind=orc-mcjit %s
|
||||
|
||||
@test = global i64 0 ; <i64*> [#uses=1]
|
||||
|
||||
define internal i64 @test.upgrd.1() {
|
||||
%tmp.0 = load i64, i64* @test ; <i64> [#uses=1]
|
||||
%tmp.1 = add i64 %tmp.0, 1 ; <i64> [#uses=1]
|
||||
ret i64 %tmp.1
|
||||
}
|
||||
|
||||
define i32 @main() {
|
||||
%L = call i64 @test.upgrd.1( ) ; <i64> [#uses=1]
|
||||
%I = trunc i64 %L to i32 ; <i32> [#uses=1]
|
||||
ret i32 %I
|
||||
}
|
||||
|
||||
|
@ -1,11 +0,0 @@
|
||||
; RUN: %lli -jit-kind=orc-mcjit %s test
|
||||
|
||||
declare i32 @puts(i8*)
|
||||
|
||||
define i32 @main(i32 %argc.1, i8** %argv.1) {
|
||||
%tmp.5 = getelementptr i8*, i8** %argv.1, i64 1 ; <i8**> [#uses=1]
|
||||
%tmp.6 = load i8*, i8** %tmp.5 ; <i8*> [#uses=1]
|
||||
%tmp.0 = call i32 @puts( i8* %tmp.6 ) ; <i32> [#uses=0]
|
||||
ret i32 0
|
||||
}
|
||||
|
@ -1,13 +0,0 @@
|
||||
; RUN: %lli -jit-kind=orc-mcjit %s > /dev/null
|
||||
|
||||
define i32 @main() {
|
||||
entry:
|
||||
br label %endif
|
||||
then: ; No predecessors!
|
||||
br label %endif
|
||||
endif: ; preds = %then, %entry
|
||||
%x = phi i32 [ 4, %entry ], [ 27, %then ] ; <i32> [#uses=0]
|
||||
%result = phi i32 [ 32, %then ], [ 0, %entry ] ; <i32> [#uses=0]
|
||||
ret i32 0
|
||||
}
|
||||
|
@ -1,17 +0,0 @@
|
||||
; RUN: %lli -jit-kind=orc-mcjit %s > /dev/null
|
||||
|
||||
; Testcase distilled from 256.bzip2.
|
||||
|
||||
define i32 @main() {
|
||||
entry:
|
||||
br label %loopentry.0
|
||||
loopentry.0: ; preds = %loopentry.0, %entry
|
||||
%h.0 = phi i32 [ %tmp.2, %loopentry.0 ], [ -1, %entry ] ; <i32> [#uses=1]
|
||||
%tmp.2 = add i32 %h.0, 1 ; <i32> [#uses=3]
|
||||
%tmp.4 = icmp ne i32 %tmp.2, 0 ; <i1> [#uses=1]
|
||||
br i1 %tmp.4, label %loopentry.0, label %loopentry.1
|
||||
loopentry.1: ; preds = %loopentry.0
|
||||
%h.1 = phi i32 [ %tmp.2, %loopentry.0 ] ; <i32> [#uses=1]
|
||||
ret i32 %h.1
|
||||
}
|
||||
|
@ -1,15 +0,0 @@
|
||||
; RUN: %lli -jit-kind=orc-mcjit %s > /dev/null
|
||||
|
||||
; Testcase distilled from 256.bzip2.
|
||||
|
||||
define i32 @main() {
|
||||
entry:
|
||||
%X = add i32 1, -1 ; <i32> [#uses=3]
|
||||
br label %Next
|
||||
Next: ; preds = %entry
|
||||
%A = phi i32 [ %X, %entry ] ; <i32> [#uses=0]
|
||||
%B = phi i32 [ %X, %entry ] ; <i32> [#uses=0]
|
||||
%C = phi i32 [ %X, %entry ] ; <i32> [#uses=1]
|
||||
ret i32 %C
|
||||
}
|
||||
|
@ -1,11 +0,0 @@
|
||||
; RUN: %lli -jit-kind=orc-mcjit %s > /dev/null
|
||||
|
||||
; This testcase failed to work because two variable sized allocas confused the
|
||||
; local register allocator.
|
||||
|
||||
define i32 @main(i32 %X) {
|
||||
%A = alloca i32, i32 %X ; <i32*> [#uses=0]
|
||||
%B = alloca float, i32 %X ; <float*> [#uses=0]
|
||||
ret i32 0
|
||||
}
|
||||
|
@ -1,21 +0,0 @@
|
||||
; RUN: %lli -jit-kind=orc-mcjit %s > /dev/null
|
||||
|
||||
;
|
||||
; Regression Test: EnvironmentTest.ll
|
||||
;
|
||||
; Description:
|
||||
; This is a regression test that verifies that the JIT passes the
|
||||
; environment to the main() function.
|
||||
;
|
||||
|
||||
|
||||
declare i32 @strlen(i8*)
|
||||
|
||||
define i32 @main(i32 %argc.1, i8** %argv.1, i8** %envp.1) {
|
||||
%tmp.2 = load i8*, i8** %envp.1 ; <i8*> [#uses=1]
|
||||
%tmp.3 = call i32 @strlen( i8* %tmp.2 ) ; <i32> [#uses=1]
|
||||
%T = icmp eq i32 %tmp.3, 0 ; <i1> [#uses=1]
|
||||
%R = zext i1 %T to i32 ; <i32> [#uses=1]
|
||||
ret i32 %R
|
||||
}
|
||||
|
@ -1,34 +0,0 @@
|
||||
; RUN: %lli -jit-kind=orc-mcjit %s > /dev/null
|
||||
|
||||
; This testcase exposes a bug in the local register allocator where it runs out
|
||||
; of registers (due to too many overlapping live ranges), but then attempts to
|
||||
; use the ESP register (which is not allocatable) to hold a value.
|
||||
|
||||
define i32 @main(i32 %A) {
|
||||
; ESP gets used again...
|
||||
%Ap2 = alloca i32, i32 %A ; <i32*> [#uses=11]
|
||||
; Produce lots of overlapping live ranges
|
||||
%B = add i32 %A, 1 ; <i32> [#uses=1]
|
||||
%C = add i32 %A, 2 ; <i32> [#uses=1]
|
||||
%D = add i32 %A, 3 ; <i32> [#uses=1]
|
||||
%E = add i32 %A, 4 ; <i32> [#uses=1]
|
||||
%F = add i32 %A, 5 ; <i32> [#uses=1]
|
||||
%G = add i32 %A, 6 ; <i32> [#uses=1]
|
||||
%H = add i32 %A, 7 ; <i32> [#uses=1]
|
||||
%I = add i32 %A, 8 ; <i32> [#uses=1]
|
||||
%J = add i32 %A, 9 ; <i32> [#uses=1]
|
||||
%K = add i32 %A, 10 ; <i32> [#uses=1]
|
||||
; Uses of all of the values
|
||||
store i32 %A, i32* %Ap2
|
||||
store i32 %B, i32* %Ap2
|
||||
store i32 %C, i32* %Ap2
|
||||
store i32 %D, i32* %Ap2
|
||||
store i32 %E, i32* %Ap2
|
||||
store i32 %F, i32* %Ap2
|
||||
store i32 %G, i32* %Ap2
|
||||
store i32 %H, i32* %Ap2
|
||||
store i32 %I, i32* %Ap2
|
||||
store i32 %J, i32* %Ap2
|
||||
store i32 %K, i32* %Ap2
|
||||
ret i32 0
|
||||
}
|
@ -1,23 +0,0 @@
|
||||
; RUN: %lli -jit-kind=orc-mcjit %s > /dev/null
|
||||
|
||||
@A = global i32 0 ; <i32*> [#uses=1]
|
||||
|
||||
define i32 @main() {
|
||||
%Ret = call i32 @test( i1 true, i32 0 ) ; <i32> [#uses=1]
|
||||
ret i32 %Ret
|
||||
}
|
||||
|
||||
define i32 @test(i1 %c, i32 %A) {
|
||||
br i1 %c, label %Taken1, label %NotTaken
|
||||
Cont: ; preds = %Taken1, %NotTaken
|
||||
%V = phi i32 [ 0, %NotTaken ], [ sub (i32 ptrtoint (i32* @A to i32), i32 1234), %Taken1 ] ; <i32> [#uses=0]
|
||||
ret i32 0
|
||||
NotTaken: ; preds = %0
|
||||
br label %Cont
|
||||
Taken1: ; preds = %0
|
||||
%B = icmp eq i32 %A, 0 ; <i1> [#uses=1]
|
||||
br i1 %B, label %Cont, label %ExitError
|
||||
ExitError: ; preds = %Taken1
|
||||
ret i32 12
|
||||
}
|
||||
|
@ -1,22 +0,0 @@
|
||||
; PR672
|
||||
; RUN: %lli -jit-kind=orc-mcjit %s
|
||||
; XFAIL: mcjit-ia32
|
||||
|
||||
define i32 @main() {
|
||||
%f = bitcast i32 (i32, i32*, i32)* @check_tail to i32* ; <i32*> [#uses=1]
|
||||
%res = tail call fastcc i32 @check_tail( i32 10, i32* %f, i32 10 ) ; <i32> [#uses=1]
|
||||
ret i32 %res
|
||||
}
|
||||
|
||||
define fastcc i32 @check_tail(i32 %x, i32* %f, i32 %g) {
|
||||
%tmp1 = icmp sgt i32 %x, 0 ; <i1> [#uses=1]
|
||||
br i1 %tmp1, label %if-then, label %if-else
|
||||
if-then: ; preds = %0
|
||||
%fun_ptr = bitcast i32* %f to i32 (i32, i32*, i32)* ; <i32 (i32, i32*, i32)*> [#uses=1]
|
||||
%arg1 = add i32 %x, -1 ; <i32> [#uses=1]
|
||||
%res = tail call fastcc i32 %fun_ptr( i32 %arg1, i32* %f, i32 %g ) ; <i32> [#uses=1]
|
||||
ret i32 %res
|
||||
if-else: ; preds = %0
|
||||
ret i32 %x
|
||||
}
|
||||
|
@ -1,19 +0,0 @@
|
||||
; RUN: %lli -jit-kind=orc-mcjit -force-interpreter %s
|
||||
; PR1836
|
||||
|
||||
define i32 @main() {
|
||||
entry:
|
||||
%retval = alloca i32 ; <i32*> [#uses=2]
|
||||
%tmp = alloca i32 ; <i32*> [#uses=2]
|
||||
%x = alloca i75, align 16 ; <i75*> [#uses=1]
|
||||
%"alloca point" = bitcast i32 0 to i32 ; <i32> [#uses=0]
|
||||
store i75 999, i75* %x, align 16
|
||||
store i32 0, i32* %tmp, align 4
|
||||
%tmp1 = load i32, i32* %tmp, align 4 ; <i32> [#uses=1]
|
||||
store i32 %tmp1, i32* %retval, align 4
|
||||
br label %return
|
||||
|
||||
return: ; preds = %entry
|
||||
%retval2 = load i32, i32* %retval ; <i32> [#uses=1]
|
||||
ret i32 %retval2
|
||||
}
|
@ -1,60 +0,0 @@
|
||||
; RUN: %lli -jit-kind=orc-mcjit -force-interpreter=true %s | FileCheck %s
|
||||
; CHECK: 1
|
||||
|
||||
target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:32:32"
|
||||
target triple = "i686-pc-linux-gnu"
|
||||
@.str = internal constant [10 x i8] c"MSB = %d\0A\00" ; <[10 x i8]*> [#uses=1]
|
||||
|
||||
define i65 @foo(i65 %x) {
|
||||
entry:
|
||||
%x_addr = alloca i65 ; <i65*> [#uses=2]
|
||||
%retval = alloca i65 ; <i65*> [#uses=2]
|
||||
%tmp = alloca i65 ; <i65*> [#uses=2]
|
||||
%"alloca point" = bitcast i65 0 to i65 ; <i65> [#uses=0]
|
||||
store i65 %x, i65* %x_addr
|
||||
%tmp1 = load i65, i65* %x_addr, align 4 ; <i65> [#uses=1]
|
||||
%tmp2 = ashr i65 %tmp1, 65 ; <i65> [#uses=1]
|
||||
store i65 %tmp2, i65* %tmp, align 4
|
||||
%tmp3 = load i65, i65* %tmp, align 4 ; <i65> [#uses=1]
|
||||
store i65 %tmp3, i65* %retval, align 4
|
||||
br label %return
|
||||
|
||||
return: ; preds = %entry
|
||||
%retval4 = load i65, i65* %retval ; <i65> [#uses=1]
|
||||
ret i65 %retval4
|
||||
}
|
||||
|
||||
define i32 @main() {
|
||||
entry:
|
||||
%retval = alloca i32 ; <i32*> [#uses=1]
|
||||
%iftmp.0 = alloca i32 ; <i32*> [#uses=3]
|
||||
%"alloca point" = bitcast i32 0 to i32 ; <i32> [#uses=0]
|
||||
%tmp = call i65 @foo( i65 -9 ) ; <i65> [#uses=1]
|
||||
%tmp1 = lshr i65 %tmp, 64 ; <i65> [#uses=1]
|
||||
%tmp2 = xor i65 %tmp1, 1 ; <i65> [#uses=1]
|
||||
%tmp3 = and i65 %tmp2, 1 ; <i65> [#uses=1]
|
||||
%tmp34 = trunc i65 %tmp3 to i8 ; <i8> [#uses=1]
|
||||
%toBool = icmp ne i8 %tmp34, 0 ; <i1> [#uses=1]
|
||||
br i1 %toBool, label %cond_true, label %cond_false
|
||||
|
||||
cond_true: ; preds = %entry
|
||||
store i32 0, i32* %iftmp.0, align 4
|
||||
br label %cond_next
|
||||
|
||||
cond_false: ; preds = %entry
|
||||
store i32 1, i32* %iftmp.0, align 4
|
||||
br label %cond_next
|
||||
|
||||
cond_next: ; preds = %cond_false, %cond_true
|
||||
%tmp5 = getelementptr [10 x i8], [10 x i8]* @.str, i32 0, i32 0 ; <i8*> [#uses=1]
|
||||
%tmp6 = load i32, i32* %iftmp.0, align 4 ; <i32> [#uses=1]
|
||||
%tmp7 = call i32 (i8*, ...) @printf( i8* noalias %tmp5, i32 %tmp6 ) nounwind ; <i32> [#uses=0]
|
||||
br label %return
|
||||
|
||||
return: ; preds = %cond_next
|
||||
store i32 0, i32* %retval, align 4
|
||||
%retval8 = load i32, i32* %retval ; <i32> [#uses=1]
|
||||
ret i32 %retval8
|
||||
}
|
||||
|
||||
declare i32 @printf(i8* noalias , ...) nounwind
|
@ -1,25 +0,0 @@
|
||||
; RUN: %lli -jit-kind=orc-mcjit %s
|
||||
;
|
||||
; Verify relocations to global symbols with addend work correctly.
|
||||
;
|
||||
; Compiled from this C code:
|
||||
;
|
||||
; int test[2] = { -1, 0 };
|
||||
; int *p = &test[1];
|
||||
;
|
||||
; int main (void)
|
||||
; {
|
||||
; return *p;
|
||||
; }
|
||||
;
|
||||
|
||||
@test = global [2 x i32] [i32 -1, i32 0], align 4
|
||||
@p = global i32* getelementptr inbounds ([2 x i32], [2 x i32]* @test, i64 0, i64 1), align 8
|
||||
|
||||
define i32 @main() {
|
||||
entry:
|
||||
%0 = load i32*, i32** @p, align 8
|
||||
%1 = load i32, i32* %0, align 4
|
||||
ret i32 %1
|
||||
}
|
||||
|
@ -1,7 +0,0 @@
|
||||
declare i32 @FA()
|
||||
|
||||
define i32 @FB() {
|
||||
%r = call i32 @FA( ) ; <i32> [#uses=1]
|
||||
ret i32 %r
|
||||
}
|
||||
|
@ -1,7 +0,0 @@
|
||||
declare i32 @FC()
|
||||
|
||||
define i32 @FB() {
|
||||
%r = call i32 @FC( ) ; <i32> [#uses=1]
|
||||
ret i32 %r
|
||||
}
|
||||
|
@ -1,4 +0,0 @@
|
||||
define i32 @FC() {
|
||||
ret i32 0
|
||||
}
|
||||
|
@ -1,30 +0,0 @@
|
||||
declare i8* @__cxa_allocate_exception(i64)
|
||||
declare void @__cxa_throw(i8*, i8*, i8*)
|
||||
declare i32 @__gxx_personality_v0(...)
|
||||
declare void @__cxa_end_catch()
|
||||
declare i8* @__cxa_begin_catch(i8*)
|
||||
|
||||
@_ZTIi = external constant i8*
|
||||
|
||||
define void @throwException_B() {
|
||||
%exception = tail call i8* @__cxa_allocate_exception(i64 4)
|
||||
call void @__cxa_throw(i8* %exception, i8* bitcast (i8** @_ZTIi to i8*), i8* null)
|
||||
unreachable
|
||||
}
|
||||
|
||||
define i32 @FB() personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) {
|
||||
entry:
|
||||
invoke void @throwException_B()
|
||||
to label %try.cont unwind label %lpad
|
||||
|
||||
lpad:
|
||||
%p = landingpad { i8*, i32 }
|
||||
catch i8* bitcast (i8** @_ZTIi to i8*)
|
||||
%e = extractvalue { i8*, i32 } %p, 0
|
||||
call i8* @__cxa_begin_catch(i8* %e)
|
||||
call void @__cxa_end_catch()
|
||||
br label %try.cont
|
||||
|
||||
try.cont:
|
||||
ret i32 0
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
define weak i32 @baz() #0 {
|
||||
entry:
|
||||
ret i32 0
|
||||
}
|
||||
|
||||
define i8* @bar() {
|
||||
entry:
|
||||
ret i8* bitcast (i32 ()* @baz to i8*)
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
; RUN: %lli -jit-kind=orc-mcjit -extra-module=%p/Inputs/cross-module-b.ll %s > /dev/null
|
||||
|
||||
declare i32 @FB()
|
||||
|
||||
define i32 @FA() {
|
||||
ret i32 0
|
||||
}
|
||||
|
||||
define i32 @main() {
|
||||
%r = call i32 @FB( ) ; <i32> [#uses=1]
|
||||
ret i32 %r
|
||||
}
|
||||
|
@ -1,14 +0,0 @@
|
||||
; RUN: %lli -jit-kind=orc-mcjit -extra-module=%p/Inputs/cross-module-b.ll -relocation-model=pic -code-model=small %s > /dev/null
|
||||
; XFAIL: mips-, mipsel-, i686, i386
|
||||
|
||||
declare i32 @FB()
|
||||
|
||||
define i32 @FA() {
|
||||
ret i32 0
|
||||
}
|
||||
|
||||
define i32 @main() {
|
||||
%r = call i32 @FB( ) ; <i32> [#uses=1]
|
||||
ret i32 %r
|
||||
}
|
||||
|
@ -1,39 +0,0 @@
|
||||
; REQUIRES: cxx-shared-library
|
||||
; RUN: %lli -jit-kind=orc-mcjit -relocation-model=pic -code-model=large %s
|
||||
; XFAIL: cygwin, windows-msvc, windows-gnu, mips-, mipsel-, i686, i386, aarch64, arm
|
||||
declare i8* @__cxa_allocate_exception(i64)
|
||||
declare void @__cxa_throw(i8*, i8*, i8*)
|
||||
declare i32 @__gxx_personality_v0(...)
|
||||
declare void @__cxa_end_catch()
|
||||
declare i8* @__cxa_begin_catch(i8*)
|
||||
|
||||
@_ZTIi = external constant i8*
|
||||
|
||||
define void @throwException() {
|
||||
%exception = tail call i8* @__cxa_allocate_exception(i64 4)
|
||||
call void @__cxa_throw(i8* %exception, i8* bitcast (i8** @_ZTIi to i8*), i8* null)
|
||||
unreachable
|
||||
}
|
||||
|
||||
; Make an internal function so we exercise R_X86_64_GOTOFF64 relocations.
|
||||
define internal dso_local void @use_gotoff() {
|
||||
ret void
|
||||
}
|
||||
|
||||
define i32 @main() personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) {
|
||||
entry:
|
||||
call void @use_gotoff()
|
||||
invoke void @throwException()
|
||||
to label %try.cont unwind label %lpad
|
||||
|
||||
lpad:
|
||||
%p = landingpad { i8*, i32 }
|
||||
catch i8* bitcast (i8** @_ZTIi to i8*)
|
||||
%e = extractvalue { i8*, i32 } %p, 0
|
||||
call i8* @__cxa_begin_catch(i8* %e)
|
||||
call void @__cxa_end_catch()
|
||||
br label %try.cont
|
||||
|
||||
try.cont:
|
||||
ret i32 0
|
||||
}
|
@ -1,33 +0,0 @@
|
||||
; REQUIRES: cxx-shared-library
|
||||
; RUN: %lli -jit-kind=orc-mcjit %s
|
||||
; XFAIL: arm, cygwin, windows-msvc, windows-gnu
|
||||
declare i8* @__cxa_allocate_exception(i64)
|
||||
declare void @__cxa_throw(i8*, i8*, i8*)
|
||||
declare i32 @__gxx_personality_v0(...)
|
||||
declare void @__cxa_end_catch()
|
||||
declare i8* @__cxa_begin_catch(i8*)
|
||||
|
||||
@_ZTIi = external constant i8*
|
||||
|
||||
define void @throwException() {
|
||||
%exception = tail call i8* @__cxa_allocate_exception(i64 4)
|
||||
call void @__cxa_throw(i8* %exception, i8* bitcast (i8** @_ZTIi to i8*), i8* null)
|
||||
unreachable
|
||||
}
|
||||
|
||||
define i32 @main() personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) {
|
||||
entry:
|
||||
invoke void @throwException()
|
||||
to label %try.cont unwind label %lpad
|
||||
|
||||
lpad:
|
||||
%p = landingpad { i8*, i32 }
|
||||
catch i8* bitcast (i8** @_ZTIi to i8*)
|
||||
%e = extractvalue { i8*, i32 } %p, 0
|
||||
call i8* @__cxa_begin_catch(i8* %e)
|
||||
call void @__cxa_end_catch()
|
||||
br label %try.cont
|
||||
|
||||
try.cont:
|
||||
ret i32 0
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
; RUN: %lli -jit-kind=orc-mcjit -force-interpreter=true %s | FileCheck %s
|
||||
; CHECK: 40091eb8
|
||||
|
||||
define i32 @test(double %x) {
|
||||
entry:
|
||||
%x46.i = bitcast double %x to i64
|
||||
%tmp343.i = lshr i64 %x46.i, 32
|
||||
%tmp344.i = trunc i64 %tmp343.i to i32
|
||||
ret i32 %tmp344.i
|
||||
}
|
||||
|
||||
define i32 @main()
|
||||
{
|
||||
%res = call i32 @test(double 3.14)
|
||||
%ptr = getelementptr [4 x i8], [4 x i8]* @format, i32 0, i32 0
|
||||
call i32 (i8*,...) @printf(i8* %ptr, i32 %res)
|
||||
ret i32 0
|
||||
}
|
||||
|
||||
declare i32 @printf(i8*, ...)
|
||||
@format = internal constant [4 x i8] c"%x\0A\00"
|
@ -1,11 +0,0 @@
|
||||
; RUN: %lli -jit-kind=orc-mcjit %s > /dev/null
|
||||
|
||||
@.LC0 = internal global [12 x i8] c"Hello World\00" ; <[12 x i8]*> [#uses=1]
|
||||
|
||||
declare i32 @puts(i8*)
|
||||
|
||||
define i32 @main() {
|
||||
%reg210 = call i32 @puts( i8* getelementptr ([12 x i8], [12 x i8]* @.LC0, i64 0, i64 0) ) ; <i32> [#uses=0]
|
||||
ret i32 0
|
||||
}
|
||||
|
@ -1,17 +0,0 @@
|
||||
; RUN: %lli -jit-kind=orc-mcjit %s > /dev/null
|
||||
|
||||
@X = global i32 7 ; <i32*> [#uses=0]
|
||||
@msg = internal global [13 x i8] c"Hello World\0A\00" ; <[13 x i8]*> [#uses=1]
|
||||
|
||||
declare void @printf([13 x i8]*, ...)
|
||||
|
||||
define void @bar() {
|
||||
call void ([13 x i8]*, ...) @printf( [13 x i8]* @msg )
|
||||
ret void
|
||||
}
|
||||
|
||||
define i32 @main() {
|
||||
call void @bar( )
|
||||
ret i32 0
|
||||
}
|
||||
|
@ -1,27 +0,0 @@
|
||||
root = config.root
|
||||
targets = root.targets
|
||||
if ('X86' in targets) | ('AArch64' in targets) | ('ARM' in targets) | \
|
||||
('Mips' in targets) | ('PowerPC' in targets) | ('SystemZ' in targets):
|
||||
config.unsupported = False
|
||||
else:
|
||||
config.unsupported = True
|
||||
|
||||
# FIXME: autoconf and cmake produce different arch names. We should normalize
|
||||
# them before getting here.
|
||||
if root.host_arch not in ['i386', 'x86', 'x86_64', 'AMD64',
|
||||
'AArch64', 'ARM', 'Mips',
|
||||
'PowerPC', 'ppc64', 'ppc64le', 'SystemZ']:
|
||||
config.unsupported = True
|
||||
|
||||
if 'armv7' in root.host_arch:
|
||||
config.unsupported = False
|
||||
|
||||
if 'i386-apple-darwin' in root.target_triple:
|
||||
config.unsupported = True
|
||||
|
||||
if 'powerpc' in root.target_triple and not 'powerpc64' in root.target_triple:
|
||||
config.unsupported = True
|
||||
|
||||
# ExecutionEngine tests are not expected to pass in a cross-compilation setup.
|
||||
if 'native' not in config.available_features:
|
||||
config.unsupported = True
|
@ -1,24 +0,0 @@
|
||||
; This first line will generate the .o files for the next run line
|
||||
; RUN: rm -rf %t.cachedir %t.cachedir2 %t.cachedir3
|
||||
; RUN: mkdir -p %t.cachedir %t.cachedir2 %t.cachedir3
|
||||
; RUN: %lli -jit-kind=orc-mcjit -extra-module=%p/Inputs/multi-module-b.ll -extra-module=%p/Inputs/multi-module-c.ll -enable-cache-manager -object-cache-dir=%t.cachedir %s
|
||||
|
||||
; Collect generated objects.
|
||||
; RUN: find %t.cachedir -type f -name 'multi-module-?.o' -exec mv -v '{}' %t.cachedir2 ';'
|
||||
|
||||
; This line tests MCJIT object loading
|
||||
; RUN: %lli -jit-kind=orc-mcjit -extra-object=%t.cachedir2/multi-module-b.o -extra-object=%t.cachedir2/multi-module-c.o %s
|
||||
|
||||
; These lines put the object files into an archive
|
||||
; RUN: llvm-ar r %t.cachedir3/load-object.a %t.cachedir2/multi-module-b.o
|
||||
; RUN: llvm-ar r %t.cachedir3/load-object.a %t.cachedir2/multi-module-c.o
|
||||
|
||||
; This line test MCJIT archive loading
|
||||
; RUN: %lli -jit-kind=orc-mcjit -extra-archive=%t.cachedir3/load-object.a %s
|
||||
|
||||
declare i32 @FB()
|
||||
|
||||
define i32 @main() {
|
||||
%r = call i32 @FB( ) ; <i32> [#uses=1]
|
||||
ret i32 %r
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
; RUN: %lli -jit-kind=orc-mcjit -extra-module=%p/Inputs/multi-module-b.ll -extra-module=%p/Inputs/multi-module-c.ll %s > /dev/null
|
||||
|
||||
declare i32 @FB()
|
||||
|
||||
define i32 @main() {
|
||||
%r = call i32 @FB( ) ; <i32> [#uses=1]
|
||||
ret i32 %r
|
||||
}
|
||||
|
@ -1,36 +0,0 @@
|
||||
; REQUIRES: cxx-shared-library
|
||||
; RUN: %lli -jit-kind=orc-mcjit -extra-module=%p/Inputs/multi-module-eh-b.ll %s
|
||||
; XFAIL: arm, cygwin, windows-msvc, windows-gnu
|
||||
declare i8* @__cxa_allocate_exception(i64)
|
||||
declare void @__cxa_throw(i8*, i8*, i8*)
|
||||
declare i32 @__gxx_personality_v0(...)
|
||||
declare void @__cxa_end_catch()
|
||||
declare i8* @__cxa_begin_catch(i8*)
|
||||
|
||||
@_ZTIi = external constant i8*
|
||||
|
||||
declare i32 @FB()
|
||||
|
||||
define void @throwException() {
|
||||
%exception = tail call i8* @__cxa_allocate_exception(i64 4)
|
||||
call void @__cxa_throw(i8* %exception, i8* bitcast (i8** @_ZTIi to i8*), i8* null)
|
||||
unreachable
|
||||
}
|
||||
|
||||
define i32 @main() personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) {
|
||||
entry:
|
||||
invoke void @throwException()
|
||||
to label %try.cont unwind label %lpad
|
||||
|
||||
lpad:
|
||||
%p = landingpad { i8*, i32 }
|
||||
catch i8* bitcast (i8** @_ZTIi to i8*)
|
||||
%e = extractvalue { i8*, i32 } %p, 0
|
||||
call i8* @__cxa_begin_catch(i8* %e)
|
||||
call void @__cxa_end_catch()
|
||||
br label %try.cont
|
||||
|
||||
try.cont:
|
||||
%r = call i32 @FB( )
|
||||
ret i32 %r
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
; RUN: %lli -jit-kind=orc-mcjit -extra-module=%p/Inputs/multi-module-b.ll -extra-module=%p/Inputs/multi-module-c.ll -relocation-model=pic -code-model=small %s > /dev/null
|
||||
; XFAIL: mips-, mipsel-, i686, i386
|
||||
|
||||
declare i32 @FB()
|
||||
|
||||
define i32 @main() {
|
||||
%r = call i32 @FB( ) ; <i32> [#uses=1]
|
||||
ret i32 %r
|
||||
}
|
||||
|
@ -1,21 +0,0 @@
|
||||
; RUN: %lli -jit-kind=orc-mcjit %s > /dev/null
|
||||
|
||||
define i32 @foo(i32 %x, i32 %y, double %d) {
|
||||
entry:
|
||||
%d.int64 = bitcast double %d to i64
|
||||
%d.top64 = lshr i64 %d.int64, 32
|
||||
%d.top = trunc i64 %d.top64 to i32
|
||||
%d.bottom = trunc i64 %d.int64 to i32
|
||||
%topCorrect = icmp eq i32 %d.top, 3735928559
|
||||
%bottomCorrect = icmp eq i32 %d.bottom, 4277009102
|
||||
%right = and i1 %topCorrect, %bottomCorrect
|
||||
%nRight = xor i1 %right, true
|
||||
%retVal = zext i1 %nRight to i32
|
||||
ret i32 %retVal
|
||||
}
|
||||
|
||||
define i32 @main() {
|
||||
entry:
|
||||
%call = call i32 @foo(i32 0, i32 1, double 0xDEADBEEFFEEDFACE)
|
||||
ret i32 %call
|
||||
}
|
@ -1,88 +0,0 @@
|
||||
; RUN: %lli -jit-kind=orc-mcjit -O0 -disable-lazy-compilation=false %s
|
||||
|
||||
; The intention of this test is to verify that symbols mapped to COMMON in ELF
|
||||
; work as expected.
|
||||
;
|
||||
; Compiled from this C code:
|
||||
;
|
||||
; int zero_int;
|
||||
; double zero_double;
|
||||
; int zero_arr[10];
|
||||
;
|
||||
; int main()
|
||||
; {
|
||||
; zero_arr[zero_int + 5] = 40;
|
||||
;
|
||||
; if (zero_double < 1.1)
|
||||
; zero_arr[zero_int + 2] = 70;
|
||||
;
|
||||
; for (int i = 1; i < 10; ++i) {
|
||||
; zero_arr[i] = zero_arr[i - 1] + zero_arr[i];
|
||||
; }
|
||||
; return zero_arr[9] == 110 ? 0 : -1;
|
||||
; }
|
||||
|
||||
@zero_int = common global i32 0, align 4
|
||||
@zero_arr = common global [10 x i32] zeroinitializer, align 16
|
||||
@zero_double = common global double 0.000000e+00, align 8
|
||||
|
||||
define i32 @main() nounwind {
|
||||
entry:
|
||||
%retval = alloca i32, align 4
|
||||
%i = alloca i32, align 4
|
||||
store i32 0, i32* %retval
|
||||
%0 = load i32, i32* @zero_int, align 4
|
||||
%add = add nsw i32 %0, 5
|
||||
%idxprom = sext i32 %add to i64
|
||||
%arrayidx = getelementptr inbounds [10 x i32], [10 x i32]* @zero_arr, i32 0, i64 %idxprom
|
||||
store i32 40, i32* %arrayidx, align 4
|
||||
%1 = load double, double* @zero_double, align 8
|
||||
%cmp = fcmp olt double %1, 1.100000e+00
|
||||
br i1 %cmp, label %if.then, label %if.end
|
||||
|
||||
if.then: ; preds = %entry
|
||||
%2 = load i32, i32* @zero_int, align 4
|
||||
%add1 = add nsw i32 %2, 2
|
||||
%idxprom2 = sext i32 %add1 to i64
|
||||
%arrayidx3 = getelementptr inbounds [10 x i32], [10 x i32]* @zero_arr, i32 0, i64 %idxprom2
|
||||
store i32 70, i32* %arrayidx3, align 4
|
||||
br label %if.end
|
||||
|
||||
if.end: ; preds = %if.then, %entry
|
||||
store i32 1, i32* %i, align 4
|
||||
br label %for.cond
|
||||
|
||||
for.cond: ; preds = %for.inc, %if.end
|
||||
%3 = load i32, i32* %i, align 4
|
||||
%cmp4 = icmp slt i32 %3, 10
|
||||
br i1 %cmp4, label %for.body, label %for.end
|
||||
|
||||
for.body: ; preds = %for.cond
|
||||
%4 = load i32, i32* %i, align 4
|
||||
%sub = sub nsw i32 %4, 1
|
||||
%idxprom5 = sext i32 %sub to i64
|
||||
%arrayidx6 = getelementptr inbounds [10 x i32], [10 x i32]* @zero_arr, i32 0, i64 %idxprom5
|
||||
%5 = load i32, i32* %arrayidx6, align 4
|
||||
%6 = load i32, i32* %i, align 4
|
||||
%idxprom7 = sext i32 %6 to i64
|
||||
%arrayidx8 = getelementptr inbounds [10 x i32], [10 x i32]* @zero_arr, i32 0, i64 %idxprom7
|
||||
%7 = load i32, i32* %arrayidx8, align 4
|
||||
%add9 = add nsw i32 %5, %7
|
||||
%8 = load i32, i32* %i, align 4
|
||||
%idxprom10 = sext i32 %8 to i64
|
||||
%arrayidx11 = getelementptr inbounds [10 x i32], [10 x i32]* @zero_arr, i32 0, i64 %idxprom10
|
||||
store i32 %add9, i32* %arrayidx11, align 4
|
||||
br label %for.inc
|
||||
|
||||
for.inc: ; preds = %for.body
|
||||
%9 = load i32, i32* %i, align 4
|
||||
%inc = add nsw i32 %9, 1
|
||||
store i32 %inc, i32* %i, align 4
|
||||
br label %for.cond
|
||||
|
||||
for.end: ; preds = %for.cond
|
||||
%10 = load i32, i32* getelementptr inbounds ([10 x i32], [10 x i32]* @zero_arr, i32 0, i64 9), align 4
|
||||
%cmp12 = icmp eq i32 %10, 110
|
||||
%cond = select i1 %cmp12, i32 0, i32 -1
|
||||
ret i32 %cond
|
||||
}
|
@ -1,28 +0,0 @@
|
||||
; RUN: %lli -jit-kind=orc-mcjit %s
|
||||
|
||||
; This test is intended to verify that a function weakly defined in
|
||||
; JITted code, and strongly defined in the main executable, can be
|
||||
; correctly resolved when called from elsewhere in JITted code.
|
||||
|
||||
; This test makes the assumption that the lli executable in compiled
|
||||
; to export symbols (e.g. --export-dynamic), and that is actually does
|
||||
; contain the symbol LLVMInitializeCodeGen. (Note that this function
|
||||
; is not actually called by the test. The test simply verifes that
|
||||
; the reference can be resolved without relocation errors.)
|
||||
|
||||
define linkonce_odr void @LLVMInitializeCodeGen() {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
define void @test() {
|
||||
entry:
|
||||
call void @LLVMInitializeCodeGen()
|
||||
ret void
|
||||
}
|
||||
|
||||
define i32 @main() {
|
||||
entry:
|
||||
ret i32 0
|
||||
}
|
||||
|
@ -1,7 +0,0 @@
|
||||
declare i32 @FA()
|
||||
|
||||
define i32 @FB() nounwind {
|
||||
%r = call i32 @FA( ) ; <i32> [#uses=1]
|
||||
ret i32 %r
|
||||
}
|
||||
|
@ -1,7 +0,0 @@
|
||||
declare i32 @FC()
|
||||
|
||||
define i32 @FB() nounwind {
|
||||
%r = call i32 @FC( ) ; <i32> [#uses=1]
|
||||
ret i32 %r
|
||||
}
|
||||
|
@ -1,4 +0,0 @@
|
||||
define i32 @FC() nounwind {
|
||||
ret i32 0
|
||||
}
|
||||
|
@ -1,15 +0,0 @@
|
||||
; RUN: %lli -jit-kind=orc-mcjit -extra-module=%p/Inputs/cross-module-b.ll -disable-lazy-compilation=true -remote-mcjit -mcjit-remote-process=lli-child-target%exeext %s > /dev/null
|
||||
; XFAIL: windows-gnu,windows-msvc
|
||||
; UNSUPPORTED: powerpc64-unknown-linux-gnu
|
||||
; Remove UNSUPPORTED for powerpc64-unknown-linux-gnu if problem caused by r266663 is fixed
|
||||
|
||||
declare i32 @FB()
|
||||
|
||||
define i32 @FA() nounwind {
|
||||
ret i32 0
|
||||
}
|
||||
|
||||
define i32 @main() nounwind {
|
||||
%r = call i32 @FB( ) ; <i32> [#uses=1]
|
||||
ret i32 %r
|
||||
}
|
@ -1,35 +0,0 @@
|
||||
; REQUIRES: cxx-shared-library
|
||||
; RUN: %lli -remote-mcjit -mcjit-remote-process=lli-child-target%exeext %s
|
||||
; XFAIL: arm, cygwin, windows-msvc, windows-gnu
|
||||
; UNSUPPORTED: powerpc64-unknown-linux-gnu
|
||||
; Remove UNSUPPORTED for powerpc64-unknown-linux-gnu if problem caused by r266663 is fixed
|
||||
declare i8* @__cxa_allocate_exception(i64)
|
||||
declare void @__cxa_throw(i8*, i8*, i8*)
|
||||
declare i32 @__gxx_personality_v0(...)
|
||||
declare void @__cxa_end_catch()
|
||||
declare i8* @__cxa_begin_catch(i8*)
|
||||
|
||||
@_ZTIi = external constant i8*
|
||||
|
||||
define void @throwException() {
|
||||
%exception = tail call i8* @__cxa_allocate_exception(i64 4)
|
||||
call void @__cxa_throw(i8* %exception, i8* bitcast (i8** @_ZTIi to i8*), i8* null)
|
||||
unreachable
|
||||
}
|
||||
|
||||
define i32 @main() personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) {
|
||||
entry:
|
||||
invoke void @throwException()
|
||||
to label %try.cont unwind label %lpad
|
||||
|
||||
lpad:
|
||||
%p = landingpad { i8*, i32 }
|
||||
catch i8* bitcast (i8** @_ZTIi to i8*)
|
||||
%e = extractvalue { i8*, i32 } %p, 0
|
||||
call i8* @__cxa_begin_catch(i8* %e)
|
||||
call void @__cxa_end_catch()
|
||||
br label %try.cont
|
||||
|
||||
try.cont:
|
||||
ret i32 0
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
if 'armv4' in config.root.target_triple or \
|
||||
'armv5' in config.root.target_triple:
|
||||
config.unsupported = True
|
||||
|
||||
# This is temporary, until Remote MCJIT works on ARM
|
||||
# See http://llvm.org/bugs/show_bug.cgi?id=18057
|
||||
#if 'armv7' in config.root.target_triple:
|
||||
# config.unsupported = True
|
@ -1,12 +0,0 @@
|
||||
; RUN: %lli -jit-kind=orc-mcjit -extra-module=%p/Inputs/multi-module-b.ll -extra-module=%p/Inputs/multi-module-c.ll -disable-lazy-compilation=true -remote-mcjit -mcjit-remote-process=lli-child-target%exeext %s > /dev/null
|
||||
; XFAIL: windows-gnu,windows-msvc
|
||||
; UNSUPPORTED: powerpc64-unknown-linux-gnu
|
||||
; Remove UNSUPPORTED for powerpc64-unknown-linux-gnu if problem caused by r266663 is fixed
|
||||
|
||||
declare i32 @FB()
|
||||
|
||||
define i32 @main() nounwind {
|
||||
%r = call i32 @FB( ) ; <i32> [#uses=1]
|
||||
ret i32 %r
|
||||
}
|
||||
|
@ -1,13 +0,0 @@
|
||||
; RUN: %lli -jit-kind=orc-mcjit -remote-mcjit -mcjit-remote-process=lli-child-target%exeext %s > /dev/null
|
||||
; XFAIL: windows-gnu,windows-msvc
|
||||
; UNSUPPORTED: powerpc64-unknown-linux-gnu
|
||||
; Remove UNSUPPORTED for powerpc64-unknown-linux-gnu if problem caused by r266663 is fixed
|
||||
|
||||
define i32 @bar() nounwind {
|
||||
ret i32 0
|
||||
}
|
||||
|
||||
define i32 @main() nounwind {
|
||||
%r = call i32 @bar( ) ; <i32> [#uses=1]
|
||||
ret i32 %r
|
||||
}
|
@ -1,38 +0,0 @@
|
||||
; RUN: %lli -jit-kind=orc-mcjit -remote-mcjit -disable-lazy-compilation=false -mcjit-remote-process=lli-child-target%exeext %s
|
||||
; XFAIL: windows-gnu,windows-msvc
|
||||
; UNSUPPORTED: powerpc64-unknown-linux-gnu
|
||||
; Remove UNSUPPORTED for powerpc64-unknown-linux-gnu if problem caused by r266663 is fixed
|
||||
|
||||
define i32 @main() nounwind {
|
||||
entry:
|
||||
call void @lazily_compiled_address_is_consistent()
|
||||
ret i32 0
|
||||
}
|
||||
|
||||
; Test PR3043: @test should have the same address before and after
|
||||
; it's JIT-compiled.
|
||||
@funcPtr = common global i1 ()* null, align 4
|
||||
@lcaic_failure = internal constant [46 x i8] c"@lazily_compiled_address_is_consistent failed\00"
|
||||
|
||||
define void @lazily_compiled_address_is_consistent() nounwind {
|
||||
entry:
|
||||
store i1 ()* @test, i1 ()** @funcPtr
|
||||
%pass = tail call i1 @test() ; <i32> [#uses=1]
|
||||
br i1 %pass, label %pass_block, label %fail_block
|
||||
pass_block:
|
||||
ret void
|
||||
fail_block:
|
||||
call i32 @puts(i8* getelementptr([46 x i8], [46 x i8]* @lcaic_failure, i32 0, i32 0))
|
||||
call void @exit(i32 1)
|
||||
unreachable
|
||||
}
|
||||
|
||||
define i1 @test() nounwind {
|
||||
entry:
|
||||
%tmp = load i1 ()*, i1 ()** @funcPtr
|
||||
%eq = icmp eq i1 ()* %tmp, @test
|
||||
ret i1 %eq
|
||||
}
|
||||
|
||||
declare i32 @puts(i8*) noreturn
|
||||
declare void @exit(i32) noreturn
|
@ -1,37 +0,0 @@
|
||||
; RUN: %lli -jit-kind=orc-mcjit -remote-mcjit -disable-lazy-compilation=false -relocation-model=pic -code-model=small %s
|
||||
; XFAIL: *
|
||||
; This function should fail until remote symbol resolution is supported.
|
||||
|
||||
define i32 @main() nounwind {
|
||||
entry:
|
||||
call void @lazily_compiled_address_is_consistent()
|
||||
ret i32 0
|
||||
}
|
||||
|
||||
; Test PR3043: @test should have the same address before and after
|
||||
; it's JIT-compiled.
|
||||
@funcPtr = common global i1 ()* null, align 4
|
||||
@lcaic_failure = internal constant [46 x i8] c"@lazily_compiled_address_is_consistent failed\00"
|
||||
|
||||
define void @lazily_compiled_address_is_consistent() nounwind {
|
||||
entry:
|
||||
store i1 ()* @test, i1 ()** @funcPtr
|
||||
%pass = tail call i1 @test() ; <i32> [#uses=1]
|
||||
br i1 %pass, label %pass_block, label %fail_block
|
||||
pass_block:
|
||||
ret void
|
||||
fail_block:
|
||||
call i32 @puts(i8* getelementptr([46 x i8], [46 x i8]* @lcaic_failure, i32 0, i32 0))
|
||||
call void @exit(i32 1)
|
||||
unreachable
|
||||
}
|
||||
|
||||
define i1 @test() nounwind {
|
||||
entry:
|
||||
%tmp = load i1 ()*, i1 ()** @funcPtr
|
||||
%eq = icmp eq i1 ()* %tmp, @test
|
||||
ret i1 %eq
|
||||
}
|
||||
|
||||
declare i32 @puts(i8*) noreturn
|
||||
declare void @exit(i32) noreturn
|
@ -1,91 +0,0 @@
|
||||
; RUN: %lli -jit-kind=orc-mcjit -remote-mcjit -O0 -disable-lazy-compilation=false -mcjit-remote-process=lli-child-target%exeext %s
|
||||
; XFAIL: windows-gnu,windows-msvc
|
||||
; UNSUPPORTED: powerpc64-unknown-linux-gnu
|
||||
; Remove UNSUPPORTED for powerpc64-unknown-linux-gnu if problem caused by r266663 is fixed
|
||||
|
||||
; The intention of this test is to verify that symbols mapped to COMMON in ELF
|
||||
; work as expected.
|
||||
;
|
||||
; Compiled from this C code:
|
||||
;
|
||||
; int zero_int;
|
||||
; double zero_double;
|
||||
; int zero_arr[10];
|
||||
;
|
||||
; int main()
|
||||
; {
|
||||
; zero_arr[zero_int + 5] = 40;
|
||||
;
|
||||
; if (zero_double < 1.0)
|
||||
; zero_arr[zero_int + 2] = 70;
|
||||
;
|
||||
; for (int i = 1; i < 10; ++i) {
|
||||
; zero_arr[i] = zero_arr[i - 1] + zero_arr[i];
|
||||
; }
|
||||
; return zero_arr[9] == 110 ? 0 : -1;
|
||||
; }
|
||||
|
||||
@zero_int = common global i32 0, align 4
|
||||
@zero_arr = common global [10 x i32] zeroinitializer, align 16
|
||||
@zero_double = common global double 0.000000e+00, align 8
|
||||
|
||||
define i32 @main() nounwind {
|
||||
entry:
|
||||
%retval = alloca i32, align 4
|
||||
%i = alloca i32, align 4
|
||||
store i32 0, i32* %retval
|
||||
%0 = load i32, i32* @zero_int, align 4
|
||||
%add = add nsw i32 %0, 5
|
||||
%idxprom = sext i32 %add to i64
|
||||
%arrayidx = getelementptr inbounds [10 x i32], [10 x i32]* @zero_arr, i32 0, i64 %idxprom
|
||||
store i32 40, i32* %arrayidx, align 4
|
||||
%1 = load double, double* @zero_double, align 8
|
||||
%cmp = fcmp olt double %1, 1.000000e+00
|
||||
br i1 %cmp, label %if.then, label %if.end
|
||||
|
||||
if.then: ; preds = %entry
|
||||
%2 = load i32, i32* @zero_int, align 4
|
||||
%add1 = add nsw i32 %2, 2
|
||||
%idxprom2 = sext i32 %add1 to i64
|
||||
%arrayidx3 = getelementptr inbounds [10 x i32], [10 x i32]* @zero_arr, i32 0, i64 %idxprom2
|
||||
store i32 70, i32* %arrayidx3, align 4
|
||||
br label %if.end
|
||||
|
||||
if.end: ; preds = %if.then, %entry
|
||||
store i32 1, i32* %i, align 4
|
||||
br label %for.cond
|
||||
|
||||
for.cond: ; preds = %for.inc, %if.end
|
||||
%3 = load i32, i32* %i, align 4
|
||||
%cmp4 = icmp slt i32 %3, 10
|
||||
br i1 %cmp4, label %for.body, label %for.end
|
||||
|
||||
for.body: ; preds = %for.cond
|
||||
%4 = load i32, i32* %i, align 4
|
||||
%sub = sub nsw i32 %4, 1
|
||||
%idxprom5 = sext i32 %sub to i64
|
||||
%arrayidx6 = getelementptr inbounds [10 x i32], [10 x i32]* @zero_arr, i32 0, i64 %idxprom5
|
||||
%5 = load i32, i32* %arrayidx6, align 4
|
||||
%6 = load i32, i32* %i, align 4
|
||||
%idxprom7 = sext i32 %6 to i64
|
||||
%arrayidx8 = getelementptr inbounds [10 x i32], [10 x i32]* @zero_arr, i32 0, i64 %idxprom7
|
||||
%7 = load i32, i32* %arrayidx8, align 4
|
||||
%add9 = add nsw i32 %5, %7
|
||||
%8 = load i32, i32* %i, align 4
|
||||
%idxprom10 = sext i32 %8 to i64
|
||||
%arrayidx11 = getelementptr inbounds [10 x i32], [10 x i32]* @zero_arr, i32 0, i64 %idxprom10
|
||||
store i32 %add9, i32* %arrayidx11, align 4
|
||||
br label %for.inc
|
||||
|
||||
for.inc: ; preds = %for.body
|
||||
%9 = load i32, i32* %i, align 4
|
||||
%inc = add nsw i32 %9, 1
|
||||
store i32 %inc, i32* %i, align 4
|
||||
br label %for.cond
|
||||
|
||||
for.end: ; preds = %for.cond
|
||||
%10 = load i32, i32* getelementptr inbounds ([10 x i32], [10 x i32]* @zero_arr, i32 0, i64 9), align 4
|
||||
%cmp12 = icmp eq i32 %10, 110
|
||||
%cond = select i1 %cmp12, i32 0, i32 -1
|
||||
ret i32 %cond
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
; RUN: %lli -jit-kind=orc-mcjit -remote-mcjit -O0 -mcjit-remote-process=lli-child-target%exeext %s
|
||||
; XFAIL: windows-gnu,windows-msvc
|
||||
; UNSUPPORTED: powerpc64-unknown-linux-gnu
|
||||
; Remove UNSUPPORTED for powerpc64-unknown-linux-gnu if problem caused by r266663 is fixed
|
||||
|
||||
; Check that a variable is always aligned as specified.
|
||||
|
||||
@var = global i32 0, align 32
|
||||
define i32 @main() nounwind {
|
||||
%addr = ptrtoint i32* @var to i64
|
||||
%mask = and i64 %addr, 31
|
||||
%tst = icmp eq i64 %mask, 0
|
||||
br i1 %tst, label %good, label %bad
|
||||
good:
|
||||
ret i32 0
|
||||
bad:
|
||||
ret i32 1
|
||||
}
|
@ -1,23 +0,0 @@
|
||||
; RUN: %lli -jit-kind=orc-mcjit -remote-mcjit -mcjit-remote-process=lli-child-target%exeext %s > /dev/null
|
||||
; XFAIL: windows-gnu,windows-msvc
|
||||
; UNSUPPORTED: powerpc64-unknown-linux-gnu
|
||||
; Remove UNSUPPORTED for powerpc64-unknown-linux-gnu if problem caused by r266663 is fixed
|
||||
|
||||
define double @test(double* %DP, double %Arg) nounwind {
|
||||
%D = load double, double* %DP ; <double> [#uses=1]
|
||||
%V = fadd double %D, 1.000000e+00 ; <double> [#uses=2]
|
||||
%W = fsub double %V, %V ; <double> [#uses=3]
|
||||
%X = fmul double %W, %W ; <double> [#uses=2]
|
||||
%Y = fdiv double %X, %X ; <double> [#uses=2]
|
||||
%Q = fadd double %Y, %Arg ; <double> [#uses=1]
|
||||
%R = bitcast double %Q to double ; <double> [#uses=1]
|
||||
store double %Q, double* %DP
|
||||
ret double %Y
|
||||
}
|
||||
|
||||
define i32 @main() nounwind {
|
||||
%X = alloca double ; <double*> [#uses=2]
|
||||
store double 0.000000e+00, double* %X
|
||||
call double @test( double* %X, double 2.000000e+00 ) ; <double>:1 [#uses=0]
|
||||
ret i32 0
|
||||
}
|
@ -1,37 +0,0 @@
|
||||
; RUN: %lli -jit-kind=orc-mcjit -remote-mcjit -mcjit-remote-process=lli-child-target%exeext %s > /dev/null
|
||||
; XFAIL: windows-gnu,windows-msvc
|
||||
; UNSUPPORTED: powerpc64-unknown-linux-gnu
|
||||
; Remove UNSUPPORTED for powerpc64-unknown-linux-gnu if problem caused by r266663 is fixed
|
||||
|
||||
@count = global i32 1, align 4
|
||||
|
||||
define i32 @main() nounwind {
|
||||
entry:
|
||||
%retval = alloca i32, align 4
|
||||
%i = alloca i32, align 4
|
||||
store i32 0, i32* %retval
|
||||
store i32 0, i32* %i, align 4
|
||||
br label %for.cond
|
||||
|
||||
for.cond: ; preds = %for.inc, %entry
|
||||
%0 = load i32, i32* %i, align 4
|
||||
%cmp = icmp slt i32 %0, 49
|
||||
br i1 %cmp, label %for.body, label %for.end
|
||||
|
||||
for.body: ; preds = %for.cond
|
||||
%1 = load i32, i32* @count, align 4
|
||||
%inc = add nsw i32 %1, 1
|
||||
store i32 %inc, i32* @count, align 4
|
||||
br label %for.inc
|
||||
|
||||
for.inc: ; preds = %for.body
|
||||
%2 = load i32, i32* %i, align 4
|
||||
%inc1 = add nsw i32 %2, 1
|
||||
store i32 %inc1, i32* %i, align 4
|
||||
br label %for.cond
|
||||
|
||||
for.end: ; preds = %for.cond
|
||||
%3 = load i32, i32* @count, align 4
|
||||
%sub = sub nsw i32 %3, 50
|
||||
ret i32 %sub
|
||||
}
|
@ -1,38 +0,0 @@
|
||||
; RUN: %lli -jit-kind=orc-mcjit -remote-mcjit -mcjit-remote-process=lli-child-target%exeext \
|
||||
; RUN: -relocation-model=pic -code-model=small %s > /dev/null
|
||||
; XFAIL: mips-, mipsel-, aarch64, arm, i686, i386, windows-gnu, windows-msvc
|
||||
; UNSUPPORTED: powerpc64-unknown-linux-gnu
|
||||
; Remove UNSUPPORTED for powerpc64-unknown-linux-gnu if problem caused by r266663 is fixed
|
||||
|
||||
@count = global i32 1, align 4
|
||||
|
||||
define i32 @main() nounwind uwtable {
|
||||
entry:
|
||||
%retval = alloca i32, align 4
|
||||
%i = alloca i32, align 4
|
||||
store i32 0, i32* %retval
|
||||
store i32 0, i32* %i, align 4
|
||||
br label %for.cond
|
||||
|
||||
for.cond: ; preds = %for.inc, %entry
|
||||
%0 = load i32, i32* %i, align 4
|
||||
%cmp = icmp slt i32 %0, 49
|
||||
br i1 %cmp, label %for.body, label %for.end
|
||||
|
||||
for.body: ; preds = %for.cond
|
||||
%1 = load i32, i32* @count, align 4
|
||||
%inc = add nsw i32 %1, 1
|
||||
store i32 %inc, i32* @count, align 4
|
||||
br label %for.inc
|
||||
|
||||
for.inc: ; preds = %for.body
|
||||
%2 = load i32, i32* %i, align 4
|
||||
%inc1 = add nsw i32 %2, 1
|
||||
store i32 %inc1, i32* %i, align 4
|
||||
br label %for.cond
|
||||
|
||||
for.end: ; preds = %for.cond
|
||||
%3 = load i32, i32* @count, align 4
|
||||
%sub = sub nsw i32 %3, 50
|
||||
ret i32 %sub
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
; RUN: %lli -jit-kind=orc-mcjit -remote-mcjit -O0 -mcjit-remote-process=lli-child-target%exeext %s
|
||||
; XFAIL: windows-gnu,windows-msvc
|
||||
; UNSUPPORTED: powerpc64-unknown-linux-gnu
|
||||
; Remove UNSUPPORTED for powerpc64-unknown-linux-gnu if problem caused by r266663 is fixed
|
||||
|
||||
@.str = private unnamed_addr constant [6 x i8] c"data1\00", align 1
|
||||
@ptr = global i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str, i32 0, i32 0), align 4
|
||||
@.str1 = private unnamed_addr constant [6 x i8] c"data2\00", align 1
|
||||
@ptr2 = global i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str1, i32 0, i32 0), align 4
|
||||
|
||||
define i32 @main(i32 %argc, i8** nocapture %argv) nounwind readonly {
|
||||
entry:
|
||||
%0 = load i8*, i8** @ptr, align 4
|
||||
%1 = load i8*, i8** @ptr2, align 4
|
||||
%cmp = icmp eq i8* %0, %1
|
||||
%. = zext i1 %cmp to i32
|
||||
ret i32 %.
|
||||
}
|
@ -1,20 +0,0 @@
|
||||
; RUN: %lli -jit-kind=orc-mcjit -remote-mcjit -mcjit-remote-process=lli-child-target%exeext \
|
||||
; RUN: -O0 -relocation-model=pic -code-model=small %s
|
||||
; XFAIL: mips-, mipsel-, aarch64, arm, i686, i386, windows-gnu, windows-msvc
|
||||
; UNSUPPORTED: powerpc64-unknown-linux-gnu
|
||||
; Remove UNSUPPORTED for powerpc64-unknown-linux-gnu if problem caused by r266663 is fixed
|
||||
|
||||
@.str = private unnamed_addr constant [6 x i8] c"data1\00", align 1
|
||||
@ptr = global i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str, i32 0, i32 0), align 4
|
||||
@.str1 = private unnamed_addr constant [6 x i8] c"data2\00", align 1
|
||||
@ptr2 = global i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str1, i32 0, i32 0), align 4
|
||||
|
||||
define i32 @main(i32 %argc, i8** nocapture %argv) nounwind readonly {
|
||||
entry:
|
||||
%0 = load i8*, i8** @ptr, align 4
|
||||
%1 = load i8*, i8** @ptr2, align 4
|
||||
%cmp = icmp eq i8* %0, %1
|
||||
%. = zext i1 %cmp to i32
|
||||
ret i32 %.
|
||||
}
|
||||
|
@ -1,6 +0,0 @@
|
||||
; RUN: %lli -jit-kind=orc-mcjit %s > /dev/null
|
||||
|
||||
define i32 @main() {
|
||||
ret i32 0
|
||||
}
|
||||
|
@ -1,11 +0,0 @@
|
||||
; RUN: %lli -jit-kind=orc-mcjit %s > /dev/null
|
||||
|
||||
define i32 @bar() {
|
||||
ret i32 0
|
||||
}
|
||||
|
||||
define i32 @main() {
|
||||
%r = call i32 @bar( ) ; <i32> [#uses=1]
|
||||
ret i32 %r
|
||||
}
|
||||
|
@ -1,36 +0,0 @@
|
||||
; RUN: %lli -jit-kind=orc-mcjit -disable-lazy-compilation=false -relocation-model=pic -code-model=small %s
|
||||
; XFAIL: mips-, mipsel-, i686, i386, aarch64, arm
|
||||
|
||||
define i32 @main() nounwind {
|
||||
entry:
|
||||
call void @lazily_compiled_address_is_consistent()
|
||||
ret i32 0
|
||||
}
|
||||
|
||||
; Test PR3043: @test should have the same address before and after
|
||||
; it's JIT-compiled.
|
||||
@funcPtr = common global i1 ()* null, align 4
|
||||
@lcaic_failure = internal constant [46 x i8] c"@lazily_compiled_address_is_consistent failed\00"
|
||||
|
||||
define void @lazily_compiled_address_is_consistent() nounwind {
|
||||
entry:
|
||||
store i1 ()* @test, i1 ()** @funcPtr
|
||||
%pass = tail call i1 @test() ; <i32> [#uses=1]
|
||||
br i1 %pass, label %pass_block, label %fail_block
|
||||
pass_block:
|
||||
ret void
|
||||
fail_block:
|
||||
call i32 @puts(i8* getelementptr([46 x i8], [46 x i8]* @lcaic_failure, i32 0, i32 0))
|
||||
call void @exit(i32 1)
|
||||
unreachable
|
||||
}
|
||||
|
||||
define i1 @test() nounwind {
|
||||
entry:
|
||||
%tmp = load i1 ()*, i1 ()** @funcPtr
|
||||
%eq = icmp eq i1 ()* %tmp, @test
|
||||
ret i1 %eq
|
||||
}
|
||||
|
||||
declare i32 @puts(i8*) noreturn
|
||||
declare void @exit(i32) noreturn
|
@ -1,35 +0,0 @@
|
||||
; RUN: %lli -jit-kind=orc-mcjit -disable-lazy-compilation=false %s
|
||||
|
||||
define i32 @main() nounwind {
|
||||
entry:
|
||||
call void @lazily_compiled_address_is_consistent()
|
||||
ret i32 0
|
||||
}
|
||||
|
||||
; Test PR3043: @test should have the same address before and after
|
||||
; it's JIT-compiled.
|
||||
@funcPtr = common global i1 ()* null, align 4
|
||||
@lcaic_failure = internal constant [46 x i8] c"@lazily_compiled_address_is_consistent failed\00"
|
||||
|
||||
define void @lazily_compiled_address_is_consistent() nounwind {
|
||||
entry:
|
||||
store i1 ()* @test, i1 ()** @funcPtr
|
||||
%pass = tail call i1 @test() ; <i32> [#uses=1]
|
||||
br i1 %pass, label %pass_block, label %fail_block
|
||||
pass_block:
|
||||
ret void
|
||||
fail_block:
|
||||
call i32 @puts(i8* getelementptr([46 x i8], [46 x i8]* @lcaic_failure, i32 0, i32 0))
|
||||
call void @exit(i32 1)
|
||||
unreachable
|
||||
}
|
||||
|
||||
define i1 @test() nounwind {
|
||||
entry:
|
||||
%tmp = load i1 ()*, i1 ()** @funcPtr
|
||||
%eq = icmp eq i1 ()* %tmp, @test
|
||||
ret i1 %eq
|
||||
}
|
||||
|
||||
declare i32 @puts(i8*) noreturn
|
||||
declare void @exit(i32) noreturn
|
@ -1,34 +0,0 @@
|
||||
; RUN: %lli -jit-kind=orc-mcjit %s > /dev/null
|
||||
|
||||
define i32 @main() {
|
||||
%A = add i8 0, 12 ; <i8> [#uses=1]
|
||||
%B = sub i8 %A, 1 ; <i8> [#uses=2]
|
||||
%C = mul i8 %B, %B ; <i8> [#uses=2]
|
||||
%D = sdiv i8 %C, %C ; <i8> [#uses=2]
|
||||
%E = srem i8 %D, %D ; <i8> [#uses=0]
|
||||
%F = udiv i8 5, 6 ; <i8> [#uses=0]
|
||||
%G = urem i8 6, 5 ; <i8> [#uses=0]
|
||||
%A.upgrd.1 = add i16 0, 12 ; <i16> [#uses=1]
|
||||
%B.upgrd.2 = sub i16 %A.upgrd.1, 1 ; <i16> [#uses=2]
|
||||
%C.upgrd.3 = mul i16 %B.upgrd.2, %B.upgrd.2 ; <i16> [#uses=2]
|
||||
%D.upgrd.4 = sdiv i16 %C.upgrd.3, %C.upgrd.3 ; <i16> [#uses=2]
|
||||
%E.upgrd.5 = srem i16 %D.upgrd.4, %D.upgrd.4 ; <i16> [#uses=0]
|
||||
%F.upgrd.6 = udiv i16 5, 6 ; <i16> [#uses=0]
|
||||
%G.upgrd.7 = urem i32 6, 5 ; <i32> [#uses=0]
|
||||
%A.upgrd.8 = add i32 0, 12 ; <i32> [#uses=1]
|
||||
%B.upgrd.9 = sub i32 %A.upgrd.8, 1 ; <i32> [#uses=2]
|
||||
%C.upgrd.10 = mul i32 %B.upgrd.9, %B.upgrd.9 ; <i32> [#uses=2]
|
||||
%D.upgrd.11 = sdiv i32 %C.upgrd.10, %C.upgrd.10 ; <i32> [#uses=2]
|
||||
%E.upgrd.12 = srem i32 %D.upgrd.11, %D.upgrd.11 ; <i32> [#uses=0]
|
||||
%F.upgrd.13 = udiv i32 5, 6 ; <i32> [#uses=0]
|
||||
%G1 = urem i32 6, 5 ; <i32> [#uses=0]
|
||||
%A.upgrd.14 = add i64 0, 12 ; <i64> [#uses=1]
|
||||
%B.upgrd.15 = sub i64 %A.upgrd.14, 1 ; <i64> [#uses=2]
|
||||
%C.upgrd.16 = mul i64 %B.upgrd.15, %B.upgrd.15 ; <i64> [#uses=2]
|
||||
%D.upgrd.17 = sdiv i64 %C.upgrd.16, %C.upgrd.16 ; <i64> [#uses=2]
|
||||
%E.upgrd.18 = srem i64 %D.upgrd.17, %D.upgrd.17 ; <i64> [#uses=0]
|
||||
%F.upgrd.19 = udiv i64 5, 6 ; <i64> [#uses=0]
|
||||
%G.upgrd.20 = urem i64 6, 5 ; <i64> [#uses=0]
|
||||
ret i32 0
|
||||
}
|
||||
|
@ -1,12 +0,0 @@
|
||||
; RUN: %lli -jit-kind=orc-mcjit %s > /dev/null
|
||||
|
||||
; test unconditional branch
|
||||
define i32 @main() {
|
||||
br label %Test
|
||||
Test: ; preds = %Test, %0
|
||||
%X = icmp eq i32 0, 4 ; <i1> [#uses=1]
|
||||
br i1 %X, label %Test, label %Label
|
||||
Label: ; preds = %Test
|
||||
ret i32 0
|
||||
}
|
||||
|
@ -1,14 +0,0 @@
|
||||
; RUN: %lli -jit-kind=orc-mcjit %s > /dev/null
|
||||
|
||||
define i32 @_Z14func_exit_codev() nounwind uwtable {
|
||||
entry:
|
||||
ret i32 0
|
||||
}
|
||||
|
||||
define i32 @main() nounwind uwtable {
|
||||
entry:
|
||||
%retval = alloca i32, align 4
|
||||
store i32 0, i32* %retval
|
||||
%call = call i32 @_Z14func_exit_codev()
|
||||
ret i32 %call
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
; RUN: %lli -jit-kind=orc-mcjit %s > /dev/null
|
||||
|
||||
declare void @exit(i32)
|
||||
|
||||
define i32 @test(i8 %C, i16 %S) {
|
||||
%X = trunc i16 %S to i8 ; <i8> [#uses=1]
|
||||
%Y = zext i8 %X to i32 ; <i32> [#uses=1]
|
||||
ret i32 %Y
|
||||
}
|
||||
|
||||
define void @FP(void (i32)* %F) {
|
||||
%X = call i32 @test( i8 123, i16 1024 ) ; <i32> [#uses=1]
|
||||
call void %F( i32 %X )
|
||||
ret void
|
||||
}
|
||||
|
||||
define i32 @main() {
|
||||
call void @FP( void (i32)* @exit )
|
||||
ret i32 1
|
||||
}
|
||||
|
@ -1,109 +0,0 @@
|
||||
; RUN: %lli -jit-kind=orc-mcjit %s > /dev/null
|
||||
|
||||
define i32 @foo() {
|
||||
ret i32 0
|
||||
}
|
||||
|
||||
define i32 @main() {
|
||||
icmp ne i1 true, false ; <i1>:1 [#uses=0]
|
||||
zext i1 true to i8 ; <i8>:2 [#uses=0]
|
||||
zext i1 true to i8 ; <i8>:3 [#uses=0]
|
||||
zext i1 true to i16 ; <i16>:4 [#uses=0]
|
||||
zext i1 true to i16 ; <i16>:5 [#uses=0]
|
||||
zext i1 true to i32 ; <i32>:6 [#uses=0]
|
||||
zext i1 true to i32 ; <i32>:7 [#uses=0]
|
||||
zext i1 true to i64 ; <i64>:8 [#uses=0]
|
||||
zext i1 true to i64 ; <i64>:9 [#uses=0]
|
||||
uitofp i1 true to float ; <float>:10 [#uses=0]
|
||||
uitofp i1 true to double ; <double>:11 [#uses=0]
|
||||
icmp ne i8 0, 0 ; <i1>:12 [#uses=0]
|
||||
icmp ne i8 1, 0 ; <i1>:13 [#uses=0]
|
||||
bitcast i8 0 to i8 ; <i8>:14 [#uses=0]
|
||||
bitcast i8 -1 to i8 ; <i8>:15 [#uses=0]
|
||||
sext i8 4 to i16 ; <i16>:16 [#uses=0]
|
||||
sext i8 4 to i16 ; <i16>:17 [#uses=0]
|
||||
sext i8 4 to i64 ; <i64>:18 [#uses=0]
|
||||
sext i8 4 to i64 ; <i64>:19 [#uses=0]
|
||||
sitofp i8 4 to float ; <float>:20 [#uses=0]
|
||||
sitofp i8 4 to double ; <double>:21 [#uses=0]
|
||||
icmp ne i8 0, 0 ; <i1>:22 [#uses=0]
|
||||
icmp ne i8 1, 0 ; <i1>:23 [#uses=0]
|
||||
bitcast i8 0 to i8 ; <i8>:24 [#uses=0]
|
||||
bitcast i8 1 to i8 ; <i8>:25 [#uses=0]
|
||||
zext i8 4 to i16 ; <i16>:26 [#uses=0]
|
||||
zext i8 4 to i16 ; <i16>:27 [#uses=0]
|
||||
zext i8 4 to i64 ; <i64>:28 [#uses=0]
|
||||
zext i8 4 to i64 ; <i64>:29 [#uses=0]
|
||||
uitofp i8 0 to float ; <float>:30 [#uses=0]
|
||||
uitofp i8 0 to double ; <double>:31 [#uses=0]
|
||||
icmp ne i16 1, 0 ; <i1>:32 [#uses=0]
|
||||
trunc i16 -1 to i8 ; <i8>:33 [#uses=0]
|
||||
trunc i16 255 to i8 ; <i8>:34 [#uses=0]
|
||||
bitcast i16 0 to i16 ; <i16>:35 [#uses=0]
|
||||
bitcast i16 0 to i16 ; <i16>:36 [#uses=0]
|
||||
sext i16 0 to i64 ; <i64>:37 [#uses=0]
|
||||
sext i16 0 to i64 ; <i64>:38 [#uses=0]
|
||||
sitofp i16 0 to float ; <float>:39 [#uses=0]
|
||||
sitofp i16 0 to double ; <double>:40 [#uses=0]
|
||||
icmp ne i16 1, 0 ; <i1>:41 [#uses=0]
|
||||
trunc i16 1 to i8 ; <i8>:42 [#uses=0]
|
||||
trunc i16 255 to i8 ; <i8>:43 [#uses=0]
|
||||
bitcast i16 0 to i16 ; <i16>:44 [#uses=0]
|
||||
bitcast i16 0 to i16 ; <i16>:45 [#uses=0]
|
||||
zext i16 0 to i64 ; <i64>:46 [#uses=0]
|
||||
zext i16 0 to i64 ; <i64>:47 [#uses=0]
|
||||
uitofp i16 0 to float ; <float>:48 [#uses=0]
|
||||
uitofp i16 0 to double ; <double>:49 [#uses=0]
|
||||
icmp ne i32 6, 0 ; <i1>:50 [#uses=0]
|
||||
trunc i32 -6 to i8 ; <i8>:51 [#uses=0]
|
||||
trunc i32 6 to i8 ; <i8>:52 [#uses=0]
|
||||
trunc i32 6 to i16 ; <i16>:53 [#uses=0]
|
||||
bitcast i32 0 to i32 ; <i32>:54 [#uses=0]
|
||||
sext i32 0 to i64 ; <i64>:55 [#uses=0]
|
||||
sext i32 0 to i64 ; <i64>:56 [#uses=0]
|
||||
sitofp i32 0 to float ; <float>:57 [#uses=0]
|
||||
sitofp i32 0 to double ; <double>:58 [#uses=0]
|
||||
icmp ne i32 6, 0 ; <i1>:59 [#uses=0]
|
||||
trunc i32 7 to i8 ; <i8>:60 [#uses=0]
|
||||
trunc i32 8 to i8 ; <i8>:61 [#uses=0]
|
||||
trunc i32 9 to i16 ; <i16>:62 [#uses=0]
|
||||
bitcast i32 10 to i32 ; <i32>:63 [#uses=0]
|
||||
zext i32 0 to i64 ; <i64>:64 [#uses=0]
|
||||
zext i32 0 to i64 ; <i64>:65 [#uses=0]
|
||||
uitofp i32 0 to float ; <float>:66 [#uses=0]
|
||||
uitofp i32 0 to double ; <double>:67 [#uses=0]
|
||||
icmp ne i64 0, 0 ; <i1>:68 [#uses=0]
|
||||
trunc i64 0 to i8 ; <i8>:69 [#uses=0]
|
||||
trunc i64 0 to i8 ; <i8>:70 [#uses=0]
|
||||
trunc i64 0 to i16 ; <i16>:71 [#uses=0]
|
||||
trunc i64 0 to i16 ; <i16>:72 [#uses=0]
|
||||
trunc i64 0 to i32 ; <i32>:73 [#uses=0]
|
||||
trunc i64 0 to i32 ; <i32>:74 [#uses=0]
|
||||
bitcast i64 0 to i64 ; <i64>:75 [#uses=0]
|
||||
bitcast i64 0 to i64 ; <i64>:76 [#uses=0]
|
||||
sitofp i64 0 to float ; <float>:77 [#uses=0]
|
||||
sitofp i64 0 to double ; <double>:78 [#uses=0]
|
||||
icmp ne i64 1, 0 ; <i1>:79 [#uses=0]
|
||||
trunc i64 1 to i8 ; <i8>:80 [#uses=0]
|
||||
trunc i64 1 to i8 ; <i8>:81 [#uses=0]
|
||||
trunc i64 1 to i16 ; <i16>:82 [#uses=0]
|
||||
trunc i64 1 to i16 ; <i16>:83 [#uses=0]
|
||||
trunc i64 1 to i32 ; <i32>:84 [#uses=0]
|
||||
trunc i64 1 to i32 ; <i32>:85 [#uses=0]
|
||||
bitcast i64 1 to i64 ; <i64>:86 [#uses=0]
|
||||
bitcast i64 1 to i64 ; <i64>:87 [#uses=0]
|
||||
uitofp i64 1 to float ; <float>:88 [#uses=0]
|
||||
uitofp i64 0 to double ; <double>:89 [#uses=0]
|
||||
bitcast float 0.000000e+00 to float ; <float>:90 [#uses=0]
|
||||
fpext float 0.000000e+00 to double ; <double>:91 [#uses=0]
|
||||
fptosi double 0.000000e+00 to i8 ; <i8>:92 [#uses=0]
|
||||
fptoui double 0.000000e+00 to i8 ; <i8>:93 [#uses=0]
|
||||
fptosi double 0.000000e+00 to i16 ; <i16>:94 [#uses=0]
|
||||
fptoui double 0.000000e+00 to i16 ; <i16>:95 [#uses=0]
|
||||
fptosi double 0.000000e+00 to i32 ; <i32>:96 [#uses=0]
|
||||
fptoui double 0.000000e+00 to i32 ; <i32>:97 [#uses=0]
|
||||
fptosi double 0.000000e+00 to i64 ; <i64>:98 [#uses=0]
|
||||
fptrunc double 0.000000e+00 to float ; <float>:99 [#uses=0]
|
||||
bitcast double 0.000000e+00 to double ; <double>:100 [#uses=0]
|
||||
ret i32 0
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
; RUN: %lli -jit-kind=orc-mcjit -O0 %s
|
||||
|
||||
; This test checks that common symbols have been allocated addresses honouring
|
||||
; the alignment requirement.
|
||||
|
||||
@CS1 = common global i32 0, align 16
|
||||
@CS2 = common global i8 0, align 1
|
||||
@CS3 = common global i32 0, align 16
|
||||
|
||||
define i32 @main() nounwind {
|
||||
entry:
|
||||
%retval = alloca i32, align 4
|
||||
%ptr = alloca i32, align 4
|
||||
store i32 0, i32* %retval
|
||||
store i32 ptrtoint (i32* @CS3 to i32), i32* %ptr, align 4
|
||||
%0 = load i32, i32* %ptr, align 4
|
||||
%and = and i32 %0, 15
|
||||
%tobool = icmp ne i32 %and, 0
|
||||
br i1 %tobool, label %if.then, label %if.else
|
||||
|
||||
if.then: ; preds = %entry
|
||||
store i32 1, i32* %retval
|
||||
br label %return
|
||||
|
||||
if.else: ; preds = %entry
|
||||
store i32 0, i32* %retval
|
||||
br label %return
|
||||
|
||||
return: ; preds = %if.else, %if.then
|
||||
%1 = load i32, i32* %retval
|
||||
ret i32 %1
|
||||
}
|
@ -1,88 +0,0 @@
|
||||
; RUN: %lli -jit-kind=orc-mcjit -O0 -disable-lazy-compilation=false %s
|
||||
|
||||
; The intention of this test is to verify that symbols mapped to COMMON in ELF
|
||||
; work as expected.
|
||||
;
|
||||
; Compiled from this C code:
|
||||
;
|
||||
; int zero_int;
|
||||
; double zero_double;
|
||||
; int zero_arr[10];
|
||||
;
|
||||
; int main()
|
||||
; {
|
||||
; zero_arr[zero_int + 5] = 40;
|
||||
;
|
||||
; if (zero_double < 1.0)
|
||||
; zero_arr[zero_int + 2] = 70;
|
||||
;
|
||||
; for (int i = 1; i < 10; ++i) {
|
||||
; zero_arr[i] = zero_arr[i - 1] + zero_arr[i];
|
||||
; }
|
||||
; return zero_arr[9] == 110 ? 0 : -1;
|
||||
; }
|
||||
|
||||
@zero_int = common global i32 0, align 4
|
||||
@zero_arr = common global [10 x i32] zeroinitializer, align 16
|
||||
@zero_double = common global double 0.000000e+00, align 8
|
||||
|
||||
define i32 @main() nounwind {
|
||||
entry:
|
||||
%retval = alloca i32, align 4
|
||||
%i = alloca i32, align 4
|
||||
store i32 0, i32* %retval
|
||||
%0 = load i32, i32* @zero_int, align 4
|
||||
%add = add nsw i32 %0, 5
|
||||
%idxprom = sext i32 %add to i64
|
||||
%arrayidx = getelementptr inbounds [10 x i32], [10 x i32]* @zero_arr, i32 0, i64 %idxprom
|
||||
store i32 40, i32* %arrayidx, align 4
|
||||
%1 = load double, double* @zero_double, align 8
|
||||
%cmp = fcmp olt double %1, 1.000000e+00
|
||||
br i1 %cmp, label %if.then, label %if.end
|
||||
|
||||
if.then: ; preds = %entry
|
||||
%2 = load i32, i32* @zero_int, align 4
|
||||
%add1 = add nsw i32 %2, 2
|
||||
%idxprom2 = sext i32 %add1 to i64
|
||||
%arrayidx3 = getelementptr inbounds [10 x i32], [10 x i32]* @zero_arr, i32 0, i64 %idxprom2
|
||||
store i32 70, i32* %arrayidx3, align 4
|
||||
br label %if.end
|
||||
|
||||
if.end: ; preds = %if.then, %entry
|
||||
store i32 1, i32* %i, align 4
|
||||
br label %for.cond
|
||||
|
||||
for.cond: ; preds = %for.inc, %if.end
|
||||
%3 = load i32, i32* %i, align 4
|
||||
%cmp4 = icmp slt i32 %3, 10
|
||||
br i1 %cmp4, label %for.body, label %for.end
|
||||
|
||||
for.body: ; preds = %for.cond
|
||||
%4 = load i32, i32* %i, align 4
|
||||
%sub = sub nsw i32 %4, 1
|
||||
%idxprom5 = sext i32 %sub to i64
|
||||
%arrayidx6 = getelementptr inbounds [10 x i32], [10 x i32]* @zero_arr, i32 0, i64 %idxprom5
|
||||
%5 = load i32, i32* %arrayidx6, align 4
|
||||
%6 = load i32, i32* %i, align 4
|
||||
%idxprom7 = sext i32 %6 to i64
|
||||
%arrayidx8 = getelementptr inbounds [10 x i32], [10 x i32]* @zero_arr, i32 0, i64 %idxprom7
|
||||
%7 = load i32, i32* %arrayidx8, align 4
|
||||
%add9 = add nsw i32 %5, %7
|
||||
%8 = load i32, i32* %i, align 4
|
||||
%idxprom10 = sext i32 %8 to i64
|
||||
%arrayidx11 = getelementptr inbounds [10 x i32], [10 x i32]* @zero_arr, i32 0, i64 %idxprom10
|
||||
store i32 %add9, i32* %arrayidx11, align 4
|
||||
br label %for.inc
|
||||
|
||||
for.inc: ; preds = %for.body
|
||||
%9 = load i32, i32* %i, align 4
|
||||
%inc = add nsw i32 %9, 1
|
||||
store i32 %inc, i32* %i, align 4
|
||||
br label %for.cond
|
||||
|
||||
for.end: ; preds = %for.cond
|
||||
%10 = load i32, i32* getelementptr inbounds ([10 x i32], [10 x i32]* @zero_arr, i32 0, i64 9), align 4
|
||||
%cmp12 = icmp eq i32 %10, 110
|
||||
%cond = select i1 %cmp12, i32 0, i32 -1
|
||||
ret i32 %cond
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
; RUN: %lli -jit-kind=orc-mcjit %s > /dev/null
|
||||
|
||||
; This tests to make sure that we can evaluate weird constant expressions
|
||||
|
||||
@A = global i32 5 ; <i32*> [#uses=1]
|
||||
@B = global i32 6 ; <i32*> [#uses=1]
|
||||
|
||||
define i32 @main() {
|
||||
%A = or i1 false, icmp slt (i32* @A, i32* @B) ; <i1> [#uses=0]
|
||||
ret i32 0
|
||||
}
|
||||
|
@ -1,15 +0,0 @@
|
||||
; RUN: %lli -jit-kind=orc-mcjit -O0 %s
|
||||
|
||||
; Check that a variable is always aligned as specified.
|
||||
|
||||
@var = global i32 0, align 32
|
||||
define i32 @main() {
|
||||
%addr = ptrtoint i32* @var to i64
|
||||
%mask = and i64 %addr, 31
|
||||
%tst = icmp eq i64 %mask, 0
|
||||
br i1 %tst, label %good, label %bad
|
||||
good:
|
||||
ret i32 0
|
||||
bad:
|
||||
ret i32 1
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
; RUN: %lli -jit-kind=orc-mcjit %s > /dev/null
|
||||
|
||||
define double @test(double* %DP, double %Arg) {
|
||||
%D = load double, double* %DP ; <double> [#uses=1]
|
||||
%V = fadd double %D, 1.000000e+00 ; <double> [#uses=2]
|
||||
%W = fsub double %V, %V ; <double> [#uses=3]
|
||||
%X = fmul double %W, %W ; <double> [#uses=2]
|
||||
%Y = fdiv double %X, %X ; <double> [#uses=2]
|
||||
%Q = fadd double %Y, %Arg ; <double> [#uses=1]
|
||||
%R = bitcast double %Q to double ; <double> [#uses=1]
|
||||
store double %Q, double* %DP
|
||||
ret double %Y
|
||||
}
|
||||
|
||||
define i32 @main() {
|
||||
%X = alloca double ; <double*> [#uses=2]
|
||||
store double 0.000000e+00, double* %X
|
||||
call double @test( double* %X, double 2.000000e+00 ) ; <double>:1 [#uses=0]
|
||||
ret i32 0
|
||||
}
|
||||
|
@ -1,23 +0,0 @@
|
||||
; RUN: %lli -jit-kind=orc-mcjit %s > /dev/null
|
||||
|
||||
define double @test(double* %DP, double %Arg) {
|
||||
%D = load double, double* %DP ; <double> [#uses=1]
|
||||
%V = fadd double %D, 1.000000e+00 ; <double> [#uses=2]
|
||||
%W = fsub double %V, %V ; <double> [#uses=3]
|
||||
%X = fmul double %W, %W ; <double> [#uses=2]
|
||||
%Y = fdiv double %X, %X ; <double> [#uses=2]
|
||||
%Z = frem double %Y, %Y ; <double> [#uses=3]
|
||||
%Z1 = fdiv double %Z, %W ; <double> [#uses=0]
|
||||
%Q = fadd double %Z, %Arg ; <double> [#uses=1]
|
||||
%R = bitcast double %Q to double ; <double> [#uses=1]
|
||||
store double %R, double* %DP
|
||||
ret double %Z
|
||||
}
|
||||
|
||||
define i32 @main() {
|
||||
%X = alloca double ; <double*> [#uses=2]
|
||||
store double 0.000000e+00, double* %X
|
||||
call double @test( double* %X, double 2.000000e+00 ) ; <double>:1 [#uses=0]
|
||||
ret i32 0
|
||||
}
|
||||
|
@ -1,22 +0,0 @@
|
||||
; RUN: %lli -jit-kind=orc-mcjit %s > /dev/null
|
||||
; XFAIL: darwin
|
||||
@var = global i32 1, align 4
|
||||
@llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 65535, void ()* @ctor_func, i8* null }]
|
||||
@llvm.global_dtors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 65535, void ()* @dtor_func, i8* null }]
|
||||
|
||||
define i32 @main() nounwind {
|
||||
entry:
|
||||
%0 = load i32, i32* @var, align 4
|
||||
ret i32 %0
|
||||
}
|
||||
|
||||
define internal void @ctor_func() section ".text.startup" {
|
||||
entry:
|
||||
store i32 0, i32* @var, align 4
|
||||
ret void
|
||||
}
|
||||
|
||||
define internal void @dtor_func() section ".text.startup" {
|
||||
entry:
|
||||
ret void
|
||||
}
|
@ -1,35 +0,0 @@
|
||||
; RUN: %lli -jit-kind=orc-mcjit -relocation-model=pic -code-model=small %s > /dev/null
|
||||
; XFAIL: mips-, mipsel-, aarch64, arm, i686, i386
|
||||
|
||||
@count = global i32 1, align 4
|
||||
|
||||
define i32 @main() nounwind uwtable {
|
||||
entry:
|
||||
%retval = alloca i32, align 4
|
||||
%i = alloca i32, align 4
|
||||
store i32 0, i32* %retval
|
||||
store i32 0, i32* %i, align 4
|
||||
br label %for.cond
|
||||
|
||||
for.cond: ; preds = %for.inc, %entry
|
||||
%0 = load i32, i32* %i, align 4
|
||||
%cmp = icmp slt i32 %0, 49
|
||||
br i1 %cmp, label %for.body, label %for.end
|
||||
|
||||
for.body: ; preds = %for.cond
|
||||
%1 = load i32, i32* @count, align 4
|
||||
%inc = add nsw i32 %1, 1
|
||||
store i32 %inc, i32* @count, align 4
|
||||
br label %for.inc
|
||||
|
||||
for.inc: ; preds = %for.body
|
||||
%2 = load i32, i32* %i, align 4
|
||||
%inc1 = add nsw i32 %2, 1
|
||||
store i32 %inc1, i32* %i, align 4
|
||||
br label %for.cond
|
||||
|
||||
for.end: ; preds = %for.cond
|
||||
%3 = load i32, i32* @count, align 4
|
||||
%sub = sub nsw i32 %3, 50
|
||||
ret i32 %sub
|
||||
}
|
@ -1,34 +0,0 @@
|
||||
; RUN: %lli -jit-kind=orc-mcjit %s > /dev/null
|
||||
|
||||
@count = global i32 1, align 4
|
||||
|
||||
define i32 @main() nounwind uwtable {
|
||||
entry:
|
||||
%retval = alloca i32, align 4
|
||||
%i = alloca i32, align 4
|
||||
store i32 0, i32* %retval
|
||||
store i32 0, i32* %i, align 4
|
||||
br label %for.cond
|
||||
|
||||
for.cond: ; preds = %for.inc, %entry
|
||||
%0 = load i32, i32* %i, align 4
|
||||
%cmp = icmp slt i32 %0, 49
|
||||
br i1 %cmp, label %for.body, label %for.end
|
||||
|
||||
for.body: ; preds = %for.cond
|
||||
%1 = load i32, i32* @count, align 4
|
||||
%inc = add nsw i32 %1, 1
|
||||
store i32 %inc, i32* @count, align 4
|
||||
br label %for.inc
|
||||
|
||||
for.inc: ; preds = %for.body
|
||||
%2 = load i32, i32* %i, align 4
|
||||
%inc1 = add nsw i32 %2, 1
|
||||
store i32 %inc1, i32* %i, align 4
|
||||
br label %for.cond
|
||||
|
||||
for.end: ; preds = %for.cond
|
||||
%3 = load i32, i32* @count, align 4
|
||||
%sub = sub nsw i32 %3, 50
|
||||
ret i32 %sub
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user