[llvm] [ORC] Support non-moving cloneToContext (PR #148688)
Jeaye Wilkerson via llvm-commits
llvm-commits at lists.llvm.org
Mon Jul 14 10:46:05 PDT 2025
https://github.com/jeaye created https://github.com/llvm/llvm-project/pull/148688
There are two usability concerns with the new `cloneToContext` from https://github.com/llvm/llvm-project/pull/146852.
1. This API assumes the LLVM context is in a `ThreadSafeContext`, but I have no need for that. My IR gen is single-threaded. IR gen (via `IRBuilder`) uses the context and module often, so I would need to do a whole lot of `withContextDo` with closures just to do things like create a new basic block.
2. The new cloning function requires a `ThreadSafeModule`, which can only be constructed by *moving* (i.e. consuming) a module. This prevents me from caching my C++ modules, which explodes the number I need to generate. Cloning should be read-only, so the module consuming here feels like it's just an implication of TSMs being used.
We can address both of these by:
1. Adding a `getContextUnlocked` to `ThreadSafeContext`, following what exists for `ThreadSafeModule`; this allows me to store a raw pointer for easy use with IR gen
2. Add an overload for `cloneToContext` which take a `const Module &` and use that as the implementation for the TSM version
@lhames for vis.
>From 8dde5ccf5561bdd81cc2f6a165cc2308857cbe78 Mon Sep 17 00:00:00 2001
From: jeaye <contact at jeaye.com>
Date: Mon, 14 Jul 2025 10:40:12 -0700
Subject: [PATCH] [ORC] Support non-moving cloneToContext
---
.../ExecutionEngine/Orc/ThreadSafeModule.h | 10 ++++
.../ExecutionEngine/Orc/ThreadSafeModule.cpp | 57 +++++++++++--------
2 files changed, 43 insertions(+), 24 deletions(-)
diff --git a/llvm/include/llvm/ExecutionEngine/Orc/ThreadSafeModule.h b/llvm/include/llvm/ExecutionEngine/Orc/ThreadSafeModule.h
index 03165895b85d0..2e5076cc4d8d6 100644
--- a/llvm/include/llvm/ExecutionEngine/Orc/ThreadSafeModule.h
+++ b/llvm/include/llvm/ExecutionEngine/Orc/ThreadSafeModule.h
@@ -62,6 +62,12 @@ class ThreadSafeContext {
return F((const LLVMContext *)nullptr);
}
+ /// Get a raw pointer to the contained context without locking the context.
+ LLVMContext *getContextUnlocked() { return S->Ctx.get(); }
+
+ /// Get a raw pointer to the contained context without locking the context.
+ const LLVMContext *getContextUnlocked() const { return S->Ctx.get(); }
+
private:
std::shared_ptr<State> S;
};
@@ -155,6 +161,10 @@ using GVModifier = std::function<void(GlobalValue &)>;
/// Clones teh given module onto the given context.
LLVM_ABI ThreadSafeModule
+cloneToContext(const Module &M, ThreadSafeContext TSCtx,
+ GVPredicate ShouldCloneDef = GVPredicate(),
+ GVModifier UpdateClonedDefSource = GVModifier());
+LLVM_ABI ThreadSafeModule
cloneToContext(const ThreadSafeModule &TSMW, ThreadSafeContext TSCtx,
GVPredicate ShouldCloneDef = GVPredicate(),
GVModifier UpdateClonedDefSource = GVModifier());
diff --git a/llvm/lib/ExecutionEngine/Orc/ThreadSafeModule.cpp b/llvm/lib/ExecutionEngine/Orc/ThreadSafeModule.cpp
index 19c000e2472a8..39ad32d8e1ef7 100644
--- a/llvm/lib/ExecutionEngine/Orc/ThreadSafeModule.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/ThreadSafeModule.cpp
@@ -14,53 +14,62 @@
namespace llvm {
namespace orc {
-ThreadSafeModule cloneToContext(const ThreadSafeModule &TSM,
+ThreadSafeModule cloneToContext(const Module &M,
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.
std::string ModuleName;
SmallVector<char, 1> ClonedModuleBuffer;
- TSM.withModuleDo([&](Module &M) {
- 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;
- });
+ 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);
+ if (UpdateClonedDefSource)
+ for (auto *GV : ClonedDefsInSrc)
+ UpdateClonedDefSource(*GV);
- BitcodeWriter BCWriter(ClonedModuleBuffer);
- BCWriter.writeModule(*Tmp);
- BCWriter.writeSymtab();
- BCWriter.writeStrtab();
- });
+ BitcodeWriter BCWriter(ClonedModuleBuffer);
+ BCWriter.writeModule(*Tmp);
+ BCWriter.writeSymtab();
+ BCWriter.writeStrtab();
MemoryBufferRef ClonedModuleBufferRef(
StringRef(ClonedModuleBuffer.data(), ClonedModuleBuffer.size()),
"cloned module buffer");
// Then parse the buffer into the new Module.
- auto M = TSCtx.withContextDo([&](LLVMContext *Ctx) {
+ auto R = 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));
+ return ThreadSafeModule(std::move(R), std::move(TSCtx));
+}
+
+ThreadSafeModule cloneToContext(const ThreadSafeModule &TSM,
+ ThreadSafeContext TSCtx,
+ GVPredicate ShouldCloneDef,
+ GVModifier UpdateClonedDefSource) {
+ assert(TSM && "Can not clone null module");
+
+ ThreadSafeModule R;
+ TSM.withModuleDo([&](Module &M) {
+ R = cloneToContext(M, TSCtx, ShouldCloneDef, UpdateClonedDefSource);
+ });
+ return R;
}
ThreadSafeModule cloneToNewContext(const ThreadSafeModule &TSM,
More information about the llvm-commits
mailing list