Skip to content

Commit 2638fa1

Browse files
authored
[ORC] Add cloneToContext: Clone Module to a given ThreadSafeContext (#146852)
This is a generalization of the existing cloneToNewContext operation: rather than cloning the given module into a new ThreadSafeContext it clones it into any given ThreadSafeContext. The given ThreadSafeContext is locked to ensure that the cloning operation is safe.
1 parent 2532bde commit 2638fa1

File tree

3 files changed

+101
-34
lines changed

3 files changed

+101
-34
lines changed

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,12 @@ class ThreadSafeModule {
153153
using GVPredicate = std::function<bool(const GlobalValue &)>;
154154
using GVModifier = std::function<void(GlobalValue &)>;
155155

156+
/// Clones teh given module onto the given context.
157+
LLVM_ABI ThreadSafeModule
158+
cloneToContext(const ThreadSafeModule &TSMW, ThreadSafeContext TSCtx,
159+
GVPredicate ShouldCloneDef = GVPredicate(),
160+
GVModifier UpdateClonedDefSource = GVModifier());
161+
156162
/// Clones the given module on to a new context.
157163
LLVM_ABI ThreadSafeModule cloneToNewContext(
158164
const ThreadSafeModule &TSMW, GVPredicate ShouldCloneDef = GVPredicate(),

llvm/lib/ExecutionEngine/Orc/ThreadSafeModule.cpp

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

17-
ThreadSafeModule cloneToNewContext(const ThreadSafeModule &TSM,
18-
GVPredicate ShouldCloneDef,
19-
GVModifier UpdateClonedDefSource) {
17+
ThreadSafeModule cloneToContext(const ThreadSafeModule &TSM,
18+
ThreadSafeContext TSCtx,
19+
GVPredicate ShouldCloneDef,
20+
GVModifier UpdateClonedDefSource) {
2021
assert(TSM && "Can not clone null module");
2122

2223
if (!ShouldCloneDef)
2324
ShouldCloneDef = [](const GlobalValue &) { return true; };
2425

25-
return TSM.withModuleDo([&](Module &M) {
26-
SmallVector<char, 1> ClonedModuleBuffer;
26+
// First copy the source module into a buffer.
27+
std::string ModuleName;
28+
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+
});
2740

28-
{
29-
std::set<GlobalValue *> ClonedDefsInSrc;
30-
ValueToValueMapTy VMap;
31-
auto Tmp = CloneModule(M, VMap, [&](const GlobalValue *GV) {
32-
if (ShouldCloneDef(*GV)) {
33-
ClonedDefsInSrc.insert(const_cast<GlobalValue *>(GV));
34-
return true;
35-
}
36-
return false;
37-
});
41+
if (UpdateClonedDefSource)
42+
for (auto *GV : ClonedDefsInSrc)
43+
UpdateClonedDefSource(*GV);
3844

39-
if (UpdateClonedDefSource)
40-
for (auto *GV : ClonedDefsInSrc)
41-
UpdateClonedDefSource(*GV);
45+
BitcodeWriter BCWriter(ClonedModuleBuffer);
46+
BCWriter.writeModule(*Tmp);
47+
BCWriter.writeSymtab();
48+
BCWriter.writeStrtab();
49+
});
50+
51+
MemoryBufferRef ClonedModuleBufferRef(
52+
StringRef(ClonedModuleBuffer.data(), ClonedModuleBuffer.size()),
53+
"cloned module buffer");
4254

43-
BitcodeWriter BCWriter(ClonedModuleBuffer);
55+
// Then parse the buffer into the new Module.
56+
auto M = TSCtx.withContextDo([&](LLVMContext *Ctx) {
57+
assert(Ctx && "No LLVMContext provided");
58+
auto TmpM = cantFail(parseBitcodeFile(ClonedModuleBufferRef, *Ctx));
59+
TmpM->setModuleIdentifier(ModuleName);
60+
return TmpM;
61+
});
4462

45-
BCWriter.writeModule(*Tmp);
46-
BCWriter.writeSymtab();
47-
BCWriter.writeStrtab();
48-
}
63+
return ThreadSafeModule(std::move(M), std::move(TSCtx));
64+
}
4965

50-
MemoryBufferRef ClonedModuleBufferRef(
51-
StringRef(ClonedModuleBuffer.data(), ClonedModuleBuffer.size()),
52-
"cloned module buffer");
53-
ThreadSafeContext NewTSCtx(std::make_unique<LLVMContext>());
66+
ThreadSafeModule cloneToNewContext(const ThreadSafeModule &TSM,
67+
GVPredicate ShouldCloneDef,
68+
GVModifier UpdateClonedDefSource) {
69+
assert(TSM && "Can not clone null module");
5470

55-
auto ClonedModule = NewTSCtx.withContextDo([&](LLVMContext *Ctx) {
56-
auto TmpM = cantFail(parseBitcodeFile(ClonedModuleBufferRef, *Ctx));
57-
TmpM->setModuleIdentifier(M.getName());
58-
return TmpM;
59-
});
60-
return ThreadSafeModule(std::move(ClonedModule), std::move(NewTSCtx));
61-
});
71+
ThreadSafeContext TSCtx(std::make_unique<LLVMContext>());
72+
return cloneToContext(TSM, std::move(TSCtx), std::move(ShouldCloneDef),
73+
std::move(UpdateClonedDefSource));
6274
}
6375

6476
} // end namespace orc

llvm/unittests/ExecutionEngine/Orc/ThreadSafeModuleTest.cpp

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,13 @@
77
//===----------------------------------------------------------------------===//
88

99
#include "llvm/ExecutionEngine/Orc/ThreadSafeModule.h"
10+
#include "llvm/IR/LLVMContext.h"
11+
#include "llvm/IR/Module.h"
12+
#include "llvm/IR/Verifier.h"
13+
#include "llvm/IRReader/IRReader.h"
14+
#include "llvm/Support/SourceMgr.h"
15+
#include "llvm/Support/raw_ostream.h"
16+
1017
#include "gtest/gtest.h"
1118

1219
#include <atomic>
@@ -18,6 +25,24 @@ using namespace llvm::orc;
1825

1926
namespace {
2027

28+
const llvm::StringRef FooSrc = R"(
29+
define void @foo() {
30+
ret void
31+
}
32+
)";
33+
34+
static ThreadSafeModule parseModule(llvm::StringRef Source,
35+
llvm::StringRef Name) {
36+
auto Ctx = std::make_unique<LLVMContext>();
37+
SMDiagnostic Err;
38+
auto M = parseIR(MemoryBufferRef(Source, Name), Err, *Ctx);
39+
if (!M) {
40+
Err.print("Testcase source failed to parse: ", errs());
41+
exit(1);
42+
}
43+
return ThreadSafeModule(std::move(M), std::move(Ctx));
44+
}
45+
2146
TEST(ThreadSafeModuleTest, ContextWhollyOwnedByOneModule) {
2247
// Test that ownership of a context can be transferred to a single
2348
// ThreadSafeModule.
@@ -103,4 +128,28 @@ TEST(ThreadSafeModuleTest, ConsumingModuleDo) {
103128
TSM.consumingModuleDo([](std::unique_ptr<Module> M) {});
104129
}
105130

131+
TEST(ThreadSafeModuleTest, CloneToNewContext) {
132+
auto TSM1 = parseModule(FooSrc, "foo.ll");
133+
auto TSM2 = cloneToNewContext(TSM1);
134+
TSM2.withModuleDo([&](Module &NewM) {
135+
EXPECT_FALSE(verifyModule(NewM, &errs()));
136+
TSM1.withModuleDo([&](Module &OrigM) {
137+
EXPECT_NE(&NewM.getContext(), &OrigM.getContext());
138+
});
139+
});
140+
}
141+
142+
TEST(ObjectFormatsTest, CloneToContext) {
143+
auto TSM1 = parseModule(FooSrc, "foo.ll");
144+
145+
auto TSCtx = ThreadSafeContext(std::make_unique<LLVMContext>());
146+
auto TSM2 = cloneToContext(TSM1, TSCtx);
147+
148+
TSM2.withModuleDo([&](Module &M) {
149+
EXPECT_FALSE(verifyModule(M, &errs()));
150+
TSCtx.withContextDo(
151+
[&](LLVMContext *Ctx) { EXPECT_EQ(&M.getContext(), Ctx); });
152+
});
153+
}
154+
106155
} // end anonymous namespace

0 commit comments

Comments
 (0)