[llvm] [ORC] Generalize RTBridge Callers to any runtime function (PR #213526)

Lang Hames via llvm-commits llvm-commits at lists.llvm.org
Sun Aug 2 03:47:47 PDT 2026


https://github.com/lhames created https://github.com/llvm/llvm-project/pull/213526

An RTBridge Caller is a controller-side handle for calling a function in the runtime. Until now the abstraction assumed every such function was a trampoline -- a runtime function whose job is to invoke *another* function at an address the controller supplies (run-as-main, run-as-int, etc.) -- so every Caller carried a dedicated ExecutorAddr parameter for that target.

Generalize Callers to call runtime functions of any shape. Invoking a supplied target is now just one kind of call, with the target address an ordinary leading argument rather than a built-in parameter: e.g. MainCaller becomes Caller<int64_t(ExecutorAddr, ArrayRef<std::string>)>.

The SPS signatures already led with an SPSExecutorAddr for the target, so this is a pure interface change -- the SPS wrappers and all call sites are unaffected. It lets Callers model runtime functions that do the work themselves, such as the memory-access wrappers, rather than only those that dispatch to another function.

>From 42fea0be3ef6cc0709c064fc867f3c6620082616 Mon Sep 17 00:00:00 2001
From: Lang Hames <lhames at gmail.com>
Date: Sun, 2 Aug 2026 20:37:35 +1000
Subject: [PATCH] [ORC] Generalize RTBridge Callers to any runtime function

An RTBridge Caller is a controller-side handle for calling a function in
the runtime. Until now the abstraction assumed every such function was a
trampoline -- a runtime function whose job is to invoke *another* function
at an address the controller supplies (run-as-main, run-as-int, etc.) -- so
every Caller carried a dedicated ExecutorAddr parameter for that target.

Generalize Callers to call runtime functions of any shape. Invoking a
supplied target is now just one kind of call, with the target address an
ordinary leading argument rather than a built-in parameter: e.g. MainCaller
becomes Caller<int64_t(ExecutorAddr, ArrayRef<std::string>)>.

The SPS signatures already led with an SPSExecutorAddr for the target, so
this is a pure interface change -- the SPS wrappers and all call sites are
unaffected. It lets Callers model runtime functions that do the work
themselves, such as the memory-access wrappers, rather than only those that
dispatch to another function.
---
 .../llvm/ExecutionEngine/Orc/RTBridge/Calls.h | 31 +++++++++----------
 .../ExecutionEngine/Orc/RTBridge/SPS/Calls.h  | 17 +++++-----
 2 files changed, 23 insertions(+), 25 deletions(-)

diff --git a/llvm/include/llvm/ExecutionEngine/Orc/RTBridge/Calls.h b/llvm/include/llvm/ExecutionEngine/Orc/RTBridge/Calls.h
index 29cf268c71803..b49e6457754bf 100644
--- a/llvm/include/llvm/ExecutionEngine/Orc/RTBridge/Calls.h
+++ b/llvm/include/llvm/ExecutionEngine/Orc/RTBridge/Calls.h
@@ -35,11 +35,9 @@ template <typename FnT> class Caller;
 /// Runtime-agnostic interface for invoking an executor-side operation with the
 /// signature RetT(ArgTs...).
 ///
-/// The operation is identified by an ExecutorAddr (the address of the
-/// executor-side function to invoke) and takes ArgTs... as arguments. Two call
-/// operators are provided: an asynchronous form that delivers the result to an
-/// OnComplete continuation, and a synchronous form that blocks until the result
-/// is available.
+/// Two call operators are provided: an asynchronous form that delivers the
+/// result to an OnComplete continuation, and a synchronous form that blocks
+/// until the result is available.
 ///
 /// A Caller abstracts over how the operation is dispatched to the executor.
 /// Concrete implementations (e.g. rt::sps::Caller) supply the dispatch
@@ -58,21 +56,21 @@ template <typename RetT, typename... ArgTs> class Caller<RetT(ArgTs...)> {
 
   virtual ~Caller() = default;
 
-  /// Asynchronously invoke the executor-side function at FnAddr with the given
-  /// Args, delivering its result (or an error) to OnComplete.
+  /// Asynchronously invoke the operation with the given Args, delivering its
+  /// result (or an error) to OnComplete.
   virtual void operator()(unique_function<void(ErrorRetT)> OnComplete,
-                          ExecutorAddr FnAddr, ArgTs... Args) = 0;
+                          ArgTs... Args) = 0;
 
-  /// Invoke the executor-side function at FnAddr with the given Args, blocking
-  /// until its result (or an error) is available.
-  ErrorRetT operator()(ExecutorAddr FnAddr, ArgTs &&...Args) {
+  /// Invoke the operation with the given Args, blocking until its result (or an
+  /// error) is available.
+  ErrorRetT operator()(ArgTs... Args) {
     using PromiseValT = std::conditional_t<std::is_void_v<RetT>, MSVCPError,
                                            MSVCPExpected<RetT>>;
     std::promise<PromiseValT> P;
     auto F = P.get_future();
     this->operator()(
         [P = std::move(P)](ErrorRetT R) mutable { P.set_value(std::move(R)); },
-        FnAddr, std::forward<ArgTs>(Args)...);
+        std::move(Args)...);
     return F.get();
   }
 };
@@ -82,14 +80,15 @@ template <typename RetT, typename... ArgTs> class Caller<RetT(ArgTs...)> {
 ///
 /// The function to run is given by its ExecutorAddr, its arguments as an
 /// argument vector, and its int64_t result is returned.
-class MainCaller : public Caller<int64_t(ArrayRef<std::string>)> {};
+class MainCaller : public Caller<int64_t(ExecutorAddr, ArrayRef<std::string>)> {
+};
 
 /// Runtime-agnostic interface for running a void() function in the executor.
 ///
 /// The function to run is given by its ExecutorAddr.
 ///
 /// WARNING: This Caller is experimental and may be removed.
-class VoidVoidCaller : public Caller<void()> {};
+class VoidVoidCaller : public Caller<void(ExecutorAddr)> {};
 
 /// Runtime-agnostic interface for running an int32_t() function in the
 /// executor.
@@ -97,7 +96,7 @@ class VoidVoidCaller : public Caller<void()> {};
 /// The function to run is given by its ExecutorAddr.
 ///
 /// WARNING: This Caller is experimental and may be removed.
-class Int32VoidCaller : public Caller<int32_t()> {};
+class Int32VoidCaller : public Caller<int32_t(ExecutorAddr)> {};
 
 /// Runtime-agnostic interface for running an int32_t(int32_t) function in the
 /// executor.
@@ -105,7 +104,7 @@ class Int32VoidCaller : public Caller<int32_t()> {};
 /// The function to run is given by its ExecutorAddr.
 ///
 /// WARNING: This Caller is experimental and may be removed.
-class Int32Int32Caller : public Caller<int32_t(int32_t)> {};
+class Int32Int32Caller : public Caller<int32_t(ExecutorAddr, int32_t)> {};
 
 } // namespace llvm::orc::rt
 
diff --git a/llvm/include/llvm/ExecutionEngine/Orc/RTBridge/SPS/Calls.h b/llvm/include/llvm/ExecutionEngine/Orc/RTBridge/SPS/Calls.h
index d11cc16a7b7e7..4102327f5d394 100644
--- a/llvm/include/llvm/ExecutionEngine/Orc/RTBridge/SPS/Calls.h
+++ b/llvm/include/llvm/ExecutionEngine/Orc/RTBridge/SPS/Calls.h
@@ -64,13 +64,12 @@ class Caller<BaseT, SPSSigT, CINameV, RetT(ArgTs...)> : public BaseT {
       return CallerSym.takeError();
   }
 
-  /// Asynchronously call the SPS wrapper at CallerFnAddr to invoke the
-  /// executor-side function at FnAddr with the given Args, delivering the
-  /// result (or an error) to OnComplete. Serialization failures are reported
-  /// through OnComplete's error channel.
+  /// Asynchronously call the SPS wrapper at CallerFnAddr with the given Args,
+  /// delivering the result (or an error) to OnComplete. Serialization failures
+  /// are reported through OnComplete's error channel.
   static void callAsync(unique_function<void(ErrorRetT)> OnComplete,
                         ExecutionSession &ES, ExecutorAddr CallerFnAddr,
-                        ExecutorAddr FnAddr, const ArgTs &...Args) {
+                        const ArgTs &...Args) {
     using namespace llvm::orc::shared;
     if constexpr (std::is_void_v<CalleeRetT>) {
       // Void result: the executor-side function produces no value, so the only
@@ -80,7 +79,7 @@ class Caller<BaseT, SPSSigT, CINameV, RetT(ArgTs...)> : public BaseT {
           [OnComplete = std::move(OnComplete)](Error SerErr) mutable {
             OnComplete(std::move(SerErr));
           },
-          FnAddr, Args...);
+          Args...);
     } else {
       ES.callSPSWrapperAsync<SPSSigT>(
           CallerFnAddr,
@@ -91,13 +90,13 @@ class Caller<BaseT, SPSSigT, CINameV, RetT(ArgTs...)> : public BaseT {
             else
               return OnComplete(std::move(Result));
           },
-          FnAddr, Args...);
+          Args...);
     }
   }
 
   void operator()(unique_function<void(ErrorRetT)> OnComplete,
-                  ExecutorAddr FnAddr, ArgTs... Args) override {
-    callAsync(std::move(OnComplete), ES, CallerFnAddr, FnAddr, Args...);
+                  ArgTs... Args) override {
+    callAsync(std::move(OnComplete), ES, CallerFnAddr, Args...);
   }
 
   using BaseT::operator();



More information about the llvm-commits mailing list