
cloneExternalModuleToContext can be used to clone an LLVM module onto a given ThreadSafeContext. Callers of this function are responsible for ensuring exclusive access to the source module and its LLVMContext.
111 lines
3.8 KiB
C++
111 lines
3.8 KiB
C++
//===-- ThreadSafeModule.cpp - Thread safe Module, Context, and Utilities -===//
|
|
//
|
|
// 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/ThreadSafeModule.h"
|
|
#include "llvm/Bitcode/BitcodeReader.h"
|
|
#include "llvm/Bitcode/BitcodeWriter.h"
|
|
#include "llvm/Transforms/Utils/Cloning.h"
|
|
|
|
namespace llvm {
|
|
namespace orc {
|
|
|
|
static std::pair<std::string, SmallVector<char, 1>>
|
|
serializeModule(const Module &M, GVPredicate ShouldCloneDef,
|
|
GVModifier UpdateClonedDefSource) {
|
|
std::string ModuleName;
|
|
SmallVector<char, 1> ClonedModuleBuffer;
|
|
|
|
ModuleName = M.getModuleIdentifier();
|
|
std::set<GlobalValue *> ClonedDefsInSrc;
|
|
ValueToValueMapTy VMap;
|
|
auto Tmp = CloneModule(M, VMap, [&](const GlobalValue *GV) {
|
|
if (ShouldCloneDef(*GV)) {
|
|
ClonedDefsInSrc.insert(const_cast<GlobalValue *>(GV));
|
|
return true;
|
|
}
|
|
return false;
|
|
});
|
|
|
|
if (UpdateClonedDefSource)
|
|
for (auto *GV : ClonedDefsInSrc)
|
|
UpdateClonedDefSource(*GV);
|
|
|
|
BitcodeWriter BCWriter(ClonedModuleBuffer);
|
|
BCWriter.writeModule(*Tmp);
|
|
BCWriter.writeSymtab();
|
|
BCWriter.writeStrtab();
|
|
|
|
return {std::move(ModuleName), std::move(ClonedModuleBuffer)};
|
|
}
|
|
|
|
ThreadSafeModule
|
|
deserializeModule(std::string ModuleName,
|
|
const SmallVector<char, 1> &ClonedModuleBuffer,
|
|
ThreadSafeContext TSCtx) {
|
|
MemoryBufferRef ClonedModuleBufferRef(
|
|
StringRef(ClonedModuleBuffer.data(), ClonedModuleBuffer.size()),
|
|
"cloned module buffer");
|
|
|
|
// Then parse the buffer into the new Module.
|
|
auto M = TSCtx.withContextDo([&](LLVMContext *Ctx) {
|
|
assert(Ctx && "No LLVMContext provided");
|
|
auto TmpM = cantFail(parseBitcodeFile(ClonedModuleBufferRef, *Ctx));
|
|
TmpM->setModuleIdentifier(ModuleName);
|
|
return TmpM;
|
|
});
|
|
|
|
return ThreadSafeModule(std::move(M), std::move(TSCtx));
|
|
}
|
|
|
|
ThreadSafeModule
|
|
cloneExternalModuleToContext(const Module &M, ThreadSafeContext TSCtx,
|
|
GVPredicate ShouldCloneDef,
|
|
GVModifier UpdateClonedDefSource) {
|
|
|
|
if (!ShouldCloneDef)
|
|
ShouldCloneDef = [](const GlobalValue &) { return true; };
|
|
|
|
auto [ModuleName, ClonedModuleBuffer] = serializeModule(
|
|
M, std::move(ShouldCloneDef), std::move(UpdateClonedDefSource));
|
|
|
|
return deserializeModule(std::move(ModuleName), ClonedModuleBuffer,
|
|
std::move(TSCtx));
|
|
}
|
|
|
|
ThreadSafeModule cloneToContext(const ThreadSafeModule &TSM,
|
|
ThreadSafeContext TSCtx,
|
|
GVPredicate ShouldCloneDef,
|
|
GVModifier UpdateClonedDefSource) {
|
|
assert(TSM && "Can not clone null module");
|
|
|
|
if (!ShouldCloneDef)
|
|
ShouldCloneDef = [](const GlobalValue &) { return true; };
|
|
|
|
// First copy the source module into a buffer.
|
|
auto [ModuleName, ClonedModuleBuffer] = TSM.withModuleDo([&](Module &M) {
|
|
return serializeModule(M, std::move(ShouldCloneDef),
|
|
std::move(UpdateClonedDefSource));
|
|
});
|
|
|
|
return deserializeModule(std::move(ModuleName), ClonedModuleBuffer,
|
|
std::move(TSCtx));
|
|
}
|
|
|
|
ThreadSafeModule cloneToNewContext(const ThreadSafeModule &TSM,
|
|
GVPredicate ShouldCloneDef,
|
|
GVModifier UpdateClonedDefSource) {
|
|
assert(TSM && "Can not clone null module");
|
|
|
|
ThreadSafeContext TSCtx(std::make_unique<LLVMContext>());
|
|
return cloneToContext(TSM, std::move(TSCtx), std::move(ShouldCloneDef),
|
|
std::move(UpdateClonedDefSource));
|
|
}
|
|
|
|
} // end namespace orc
|
|
} // end namespace llvm
|