Skip to content

Commit 3bc3b4c

Browse files
committed
[ORC] Add cloneExternalModuleToContext API.
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.
1 parent f5b36eb commit 3bc3b4c

File tree

3 files changed

+95
-34
lines changed

3 files changed

+95
-34
lines changed

llvm/include/llvm/ExecutionEngine/Orc/ThreadSafeModule.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,14 @@ cloneToContext(const ThreadSafeModule &TSMW, ThreadSafeContext TSCtx,
159159
GVPredicate ShouldCloneDef = GVPredicate(),
160160
GVModifier UpdateClonedDefSource = GVModifier());
161161

162+
/// Clone the given module onto the given context.
163+
/// The caller is responsible for ensuring that the source module and its
164+
/// LLVMContext will not be concurrently accessed during the clone.
165+
LLVM_ABI ThreadSafeModule
166+
cloneExternalModuleToContext(const Module &M, ThreadSafeContext TSCtx,
167+
GVPredicate ShouldCloneDef = GVPredicate(),
168+
GVModifier UpdateClonedDefSource = GVModifier());
169+
162170
/// Clones the given module on to a new context.
163171
LLVM_ABI ThreadSafeModule cloneToNewContext(
164172
const ThreadSafeModule &TSMW, GVPredicate ShouldCloneDef = GVPredicate(),

llvm/lib/ExecutionEngine/Orc/ThreadSafeModule.cpp

Lines changed: 63 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -14,40 +14,39 @@
1414
namespace llvm {
1515
namespace orc {
1616

17-
ThreadSafeModule cloneToContext(const ThreadSafeModule &TSM,
18-
ThreadSafeContext TSCtx,
19-
GVPredicate ShouldCloneDef,
20-
GVModifier UpdateClonedDefSource) {
21-
assert(TSM && "Can not clone null module");
22-
23-
if (!ShouldCloneDef)
24-
ShouldCloneDef = [](const GlobalValue &) { return true; };
25-
26-
// First copy the source module into a buffer.
17+
static std::pair<std::string, SmallVector<char, 1>>
18+
serializeModule(const Module &M, GVPredicate ShouldCloneDef,
19+
GVModifier UpdateClonedDefSource) {
2720
std::string ModuleName;
2821
SmallVector<char, 1> ClonedModuleBuffer;
29-
TSM.withModuleDo([&](Module &M) {
30-
ModuleName = M.getModuleIdentifier();
31-
std::set<GlobalValue *> ClonedDefsInSrc;
32-
ValueToValueMapTy VMap;
33-
auto Tmp = CloneModule(M, VMap, [&](const GlobalValue *GV) {
34-
if (ShouldCloneDef(*GV)) {
35-
ClonedDefsInSrc.insert(const_cast<GlobalValue *>(GV));
36-
return true;
37-
}
38-
return false;
39-
});
40-
41-
if (UpdateClonedDefSource)
42-
for (auto *GV : ClonedDefsInSrc)
43-
UpdateClonedDefSource(*GV);
44-
45-
BitcodeWriter BCWriter(ClonedModuleBuffer);
46-
BCWriter.writeModule(*Tmp);
47-
BCWriter.writeSymtab();
48-
BCWriter.writeStrtab();
22+
23+
ModuleName = M.getModuleIdentifier();
24+
std::set<GlobalValue *> ClonedDefsInSrc;
25+
ValueToValueMapTy VMap;
26+
auto Tmp = CloneModule(M, VMap, [&](const GlobalValue *GV) {
27+
if (ShouldCloneDef(*GV)) {
28+
ClonedDefsInSrc.insert(const_cast<GlobalValue *>(GV));
29+
return true;
30+
}
31+
return false;
4932
});
5033

34+
if (UpdateClonedDefSource)
35+
for (auto *GV : ClonedDefsInSrc)
36+
UpdateClonedDefSource(*GV);
37+
38+
BitcodeWriter BCWriter(ClonedModuleBuffer);
39+
BCWriter.writeModule(*Tmp);
40+
BCWriter.writeSymtab();
41+
BCWriter.writeStrtab();
42+
43+
return {std::move(ModuleName), std::move(ClonedModuleBuffer)};
44+
}
45+
46+
ThreadSafeModule
47+
deserializeModule(std::string ModuleName,
48+
const SmallVector<char, 1> &ClonedModuleBuffer,
49+
ThreadSafeContext TSCtx) {
5150
MemoryBufferRef ClonedModuleBufferRef(
5251
StringRef(ClonedModuleBuffer.data(), ClonedModuleBuffer.size()),
5352
"cloned module buffer");
@@ -63,6 +62,40 @@ ThreadSafeModule cloneToContext(const ThreadSafeModule &TSM,
6362
return ThreadSafeModule(std::move(M), std::move(TSCtx));
6463
}
6564

65+
ThreadSafeModule
66+
cloneExternalModuleToContext(const Module &M, ThreadSafeContext TSCtx,
67+
GVPredicate ShouldCloneDef,
68+
GVModifier UpdateClonedDefSource) {
69+
70+
if (!ShouldCloneDef)
71+
ShouldCloneDef = [](const GlobalValue &) { return true; };
72+
73+
auto [ModuleName, ClonedModuleBuffer] = serializeModule(
74+
M, std::move(ShouldCloneDef), std::move(UpdateClonedDefSource));
75+
76+
return deserializeModule(std::move(ModuleName), ClonedModuleBuffer,
77+
std::move(TSCtx));
78+
}
79+
80+
ThreadSafeModule cloneToContext(const ThreadSafeModule &TSM,
81+
ThreadSafeContext TSCtx,
82+
GVPredicate ShouldCloneDef,
83+
GVModifier UpdateClonedDefSource) {
84+
assert(TSM && "Can not clone null module");
85+
86+
if (!ShouldCloneDef)
87+
ShouldCloneDef = [](const GlobalValue &) { return true; };
88+
89+
// First copy the source module into a buffer.
90+
auto [ModuleName, ClonedModuleBuffer] = TSM.withModuleDo([&](Module &M) {
91+
return serializeModule(M, std::move(ShouldCloneDef),
92+
std::move(UpdateClonedDefSource));
93+
});
94+
95+
return deserializeModule(std::move(ModuleName), ClonedModuleBuffer,
96+
std::move(TSCtx));
97+
}
98+
6699
ThreadSafeModule cloneToNewContext(const ThreadSafeModule &TSM,
67100
GVPredicate ShouldCloneDef,
68101
GVModifier UpdateClonedDefSource) {

llvm/unittests/ExecutionEngine/Orc/ThreadSafeModuleTest.cpp

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,15 +31,21 @@ const llvm::StringRef FooSrc = R"(
3131
}
3232
)";
3333

34-
static ThreadSafeModule parseModule(llvm::StringRef Source,
35-
llvm::StringRef Name) {
36-
auto Ctx = std::make_unique<LLVMContext>();
34+
static std::unique_ptr<Module>
35+
parseModuleRaw(llvm::StringRef Source, llvm::StringRef Name, LLVMContext &Ctx) {
3736
SMDiagnostic Err;
38-
auto M = parseIR(MemoryBufferRef(Source, Name), Err, *Ctx);
37+
auto M = parseIR(MemoryBufferRef(Source, Name), Err, Ctx);
3938
if (!M) {
4039
Err.print("Testcase source failed to parse: ", errs());
4140
exit(1);
4241
}
42+
return M;
43+
}
44+
45+
static ThreadSafeModule parseModule(llvm::StringRef Source,
46+
llvm::StringRef Name) {
47+
auto Ctx = std::make_unique<LLVMContext>();
48+
auto M = parseModuleRaw(Source, Name, *Ctx);
4349
return ThreadSafeModule(std::move(M), std::move(Ctx));
4450
}
4551

@@ -128,6 +134,20 @@ TEST(ThreadSafeModuleTest, ConsumingModuleDo) {
128134
TSM.consumingModuleDo([](std::unique_ptr<Module> M) {});
129135
}
130136

137+
TEST(ThreadSafeModuleTest, CloneExternalModuleToNewContext) {
138+
auto Ctx = std::make_unique<LLVMContext>();
139+
auto M = parseModuleRaw(FooSrc, "foo.ll", *Ctx);
140+
auto TSCtx = ThreadSafeContext(std::make_unique<LLVMContext>());
141+
auto TSM = cloneExternalModuleToContext(*M, TSCtx);
142+
TSM.withModuleDo([&](Module &NewM) {
143+
EXPECT_NE(&NewM.getContext(), Ctx.get());
144+
TSCtx.withContextDo(
145+
[&](LLVMContext *NewCtx) { EXPECT_EQ(&NewM.getContext(), NewCtx); });
146+
EXPECT_FALSE(NewM.empty());
147+
EXPECT_FALSE(verifyModule(NewM, &errs()));
148+
});
149+
}
150+
131151
TEST(ThreadSafeModuleTest, CloneToNewContext) {
132152
auto TSM1 = parseModule(FooSrc, "foo.ll");
133153
auto TSM2 = cloneToNewContext(TSM1);

0 commit comments

Comments
 (0)