[llvm] [orc-rt] Enable transparent SPS conversion for ptrs via ExecutorAddr. (PR #162069)

Lang Hames via llvm-commits llvm-commits at lists.llvm.org
Mon Oct 6 04:20:25 PDT 2025


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

Allows SPS wrapper function calls and handles to use pointer arguments. These will be converted to ExecutorAddr for serialization / deserialization.

>From 77067a8f8b63a20fc0a71bb7d0ad0018ae098ed3 Mon Sep 17 00:00:00 2001
From: Lang Hames <lhames at gmail.com>
Date: Mon, 6 Oct 2025 22:05:33 +1100
Subject: [PATCH] [orc-rt] Enable transparent SPS conversion for ptrs via
 ExecutorAddr.

Allows SPS wrapper function calls and handles to use pointer arguments. These
will be converted to ExecutorAddr for serialization / deserialization.
---
 orc-rt/include/orc-rt/SPSWrapperFunction.h  | 72 ++++++++++++---------
 orc-rt/unittests/SPSWrapperFunctionTest.cpp | 21 ++++++
 2 files changed, 62 insertions(+), 31 deletions(-)

diff --git a/orc-rt/include/orc-rt/SPSWrapperFunction.h b/orc-rt/include/orc-rt/SPSWrapperFunction.h
index 275e253330f20..e5ed14f5cd721 100644
--- a/orc-rt/include/orc-rt/SPSWrapperFunction.h
+++ b/orc-rt/include/orc-rt/SPSWrapperFunction.h
@@ -33,47 +33,61 @@ template <typename... SPSArgTs> struct WFSPSHelper {
     return std::move(R);
   }
 
-  template <typename T> static const T &toSerializable(const T &Arg) noexcept {
-    return Arg;
-  }
+  template <typename T> struct Serializable {
+    typedef std::decay_t<T> serializable_type;
+    static const T &to(const T &Arg) noexcept { return Arg; }
+    static T &&from(T &&Arg) noexcept { return std::forward<T>(Arg); }
+  };
 
-  static SPSSerializableError toSerializable(Error Err) {
-    return SPSSerializableError(std::move(Err));
-  }
+  template <typename T> struct Serializable<T *> {
+    typedef ExecutorAddr serializable_type;
+    static ExecutorAddr to(T *Arg) { return ExecutorAddr::fromPtr(Arg); }
+    static T *from(ExecutorAddr A) { return A.toPtr<T *>(); }
+  };
 
-  template <typename T>
-  static SPSSerializableExpected<T> toSerializable(Expected<T> Arg) {
-    return SPSSerializableExpected<T>(std::move(Arg));
-  }
+  template <> struct Serializable<Error> {
+    typedef SPSSerializableError serializable_type;
+    static SPSSerializableError to(Error Err) {
+      return SPSSerializableError(std::move(Err));
+    }
+    static Error from(SPSSerializableError Err) { return Err.toError(); }
+  };
+
+  template <typename T> struct Serializable<Expected<T>> {
+    typedef SPSSerializableExpected<T> serializable_type;
+    static SPSSerializableExpected<T> to(Expected<T> Val) {
+      return SPSSerializableExpected<T>(std::move(Val));
+    }
+    static Expected<T> from(SPSSerializableExpected<T> Val) {
+      return Val.toExpected();
+    }
+  };
 
   template <typename... Ts> struct DeserializableTuple;
 
   template <typename... Ts> struct DeserializableTuple<std::tuple<Ts...>> {
-    typedef std::tuple<
-        std::decay_t<decltype(toSerializable(std::declval<Ts>()))>...>
-        type;
+    typedef std::tuple<typename Serializable<Ts>::serializable_type...> type;
   };
 
   template <typename... Ts>
   using DeserializableTuple_t = typename DeserializableTuple<Ts...>::type;
 
-  template <typename T> static T &&fromSerializable(T &&Arg) noexcept {
-    return std::forward<T>(Arg);
-  }
-
-  static Error fromSerializable(SPSSerializableError Err) {
-    return Err.toError();
-  }
-
-  template <typename T>
-  static Expected<T> fromSerializable(SPSSerializableExpected<T> Val) {
-    return Val.toExpected();
+  template <typename ArgTuple, typename... SerializableArgs, std::size_t... Is>
+  std::optional<ArgTuple>
+  applySerializationConversions(std::tuple<SerializableArgs...> &Inputs,
+                                std::index_sequence<Is...>) {
+    static_assert(sizeof...(SerializableArgs) ==
+                      std::index_sequence<Is...>::size(),
+                  "Tuple sizes don't match");
+    return std::optional<ArgTuple>(
+        std::in_place, Serializable<std::tuple_element_t<Is, ArgTuple>>::from(
+                           std::move(std::get<Is>(Inputs)))...);
   }
 
 public:
   template <typename... ArgTs>
   std::optional<WrapperFunctionBuffer> serialize(ArgTs &&...Args) {
-    return serializeImpl(toSerializable(std::forward<ArgTs>(Args))...);
+    return serializeImpl(Serializable<ArgTs>::to(std::forward<ArgTs>(Args))...);
   }
 
   template <typename ArgTuple>
@@ -85,12 +99,8 @@ template <typename... SPSArgTs> struct WFSPSHelper {
     if (!SPSSerializationTraits<SPSTuple<SPSArgTs...>,
                                 decltype(Args)>::deserialize(IB, Args))
       return std::nullopt;
-    return std::apply(
-        [](auto &&...A) {
-          return std::optional<ArgTuple>(std::in_place,
-                                         std::move(fromSerializable(A))...);
-        },
-        std::move(Args));
+    return applySerializationConversions<ArgTuple>(
+        Args, std::make_index_sequence<std::tuple_size_v<ArgTuple>>());
   }
 };
 
diff --git a/orc-rt/unittests/SPSWrapperFunctionTest.cpp b/orc-rt/unittests/SPSWrapperFunctionTest.cpp
index e010e2a067adf..a8409cc10052f 100644
--- a/orc-rt/unittests/SPSWrapperFunctionTest.cpp
+++ b/orc-rt/unittests/SPSWrapperFunctionTest.cpp
@@ -221,6 +221,27 @@ TEST(SPSWrapperFunctionUtilsTest, TestFunctionReturningExpectedFailureCase) {
   EXPECT_EQ(ErrMsg, "N is not a multiple of 2");
 }
 
+static void
+round_trip_int_pointer_sps_wrapper(orc_rt_SessionRef Session, void *CallCtx,
+                                   orc_rt_WrapperFunctionReturn Return,
+                                   orc_rt_WrapperFunctionBuffer ArgBytes) {
+  SPSWrapperFunction<SPSExecutorAddr(SPSExecutorAddr)>::handle(
+      Session, CallCtx, Return, ArgBytes,
+      [](move_only_function<void(int32_t *)> Return, int32_t *P) {
+        Return(P);
+      });
+}
+
+TEST(SPSWrapperFunctionUtilsTest, TestTransparentSerializationForPointers) {
+  int X = 42;
+  int *P = nullptr;
+  SPSWrapperFunction<SPSExecutorAddr(SPSExecutorAddr)>::call(
+      DirectCaller(nullptr, round_trip_int_pointer_sps_wrapper),
+      [&](Expected<int32_t *> R) { P = cantFail(std::move(R)); }, &X);
+
+  EXPECT_EQ(P, &X);
+}
+
 template <size_t N> struct SPSOpCounter {};
 
 namespace orc_rt {



More information about the llvm-commits mailing list