[llvm] [ORC] Add void function support to CallViaEPC, CallSPSViaEPC. (PR #170800)
Lang Hames via llvm-commits
llvm-commits at lists.llvm.org
Thu Dec 4 21:11:09 PST 2025
https://github.com/lhames created https://github.com/llvm/llvm-project/pull/170800
Adds support for calling void functions. Calls to void functions return Error to capture any IPC/RPC failure.
>From e0989ef495c837343e4917f2a83389a672d8cfc7 Mon Sep 17 00:00:00 2001
From: Lang Hames <lhames at gmail.com>
Date: Fri, 5 Dec 2025 07:53:08 +1100
Subject: [PATCH] [ORC] Add void function support to CallViaEPC, CallSPSViaEPC.
Adds support for calling void functions. Calls to void functions return Error
to capture any IPC/RPC failure.
---
.../llvm/ExecutionEngine/Orc/CallSPSViaEPC.h | 44 +++++++++++++------
.../llvm/ExecutionEngine/Orc/CallViaEPC.h | 30 ++++++++++---
.../ExecutionEngine/Orc/CallSPSViaEPCTest.cpp | 26 +++++++++++
3 files changed, 80 insertions(+), 20 deletions(-)
diff --git a/llvm/include/llvm/ExecutionEngine/Orc/CallSPSViaEPC.h b/llvm/include/llvm/ExecutionEngine/Orc/CallSPSViaEPC.h
index 978c9be06ad98..768d0b3ec1000 100644
--- a/llvm/include/llvm/ExecutionEngine/Orc/CallSPSViaEPC.h
+++ b/llvm/include/llvm/ExecutionEngine/Orc/CallSPSViaEPC.h
@@ -20,22 +20,13 @@
namespace llvm::orc {
namespace detail {
-template <typename RetT, typename... ArgTs> struct SPSCallSerializationImpl {
- using RetSerialization = shared::SPSArgList<RetT>;
- using ArgSerialization = shared::SPSArgList<ArgTs...>;
-};
-} // namespace detail
-
-template <typename SPSSig>
-struct SPSCallSerialization
- : public CallableTraitsHelper<detail::SPSCallSerializationImpl, SPSSig> {};
+template <typename SPSRetT, typename... SPSArgTs>
+struct SPSCallSerializationImpl {
+ using RetSerialization = shared::SPSArgList<SPSRetT>;
+ using ArgSerialization = shared::SPSArgList<SPSArgTs...>;
-template <typename SPSSig> class SPSCallSerializer {
-public:
template <typename... ArgTs>
Expected<shared::WrapperFunctionResult> serialize(ArgTs &&...Args) {
- using ArgSerialization =
- typename SPSCallSerialization<SPSSig>::ArgSerialization;
auto Buffer = shared::WrapperFunctionResult::allocate(
ArgSerialization::size(Args...));
shared::SPSOutputBuffer OB(Buffer.data(), Buffer.size());
@@ -44,11 +35,22 @@ template <typename SPSSig> class SPSCallSerializer {
inconvertibleErrorCode());
return std::move(Buffer);
}
+};
+
+template <typename SPSSig>
+struct SPSCallSerialization
+ : public CallableTraitsHelper<detail::SPSCallSerializationImpl, SPSSig> {};
+
+} // namespace detail
+
+/// SPS serialization for non-void calls.
+template <typename SPSSig>
+struct SPSCallSerializer : public detail::SPSCallSerialization<SPSSig> {
template <typename RetT>
Expected<RetT> deserialize(shared::WrapperFunctionResult ResultBytes) {
using RetDeserialization =
- typename SPSCallSerialization<SPSSig>::RetSerialization;
+ typename detail::SPSCallSerialization<SPSSig>::RetSerialization;
shared::SPSInputBuffer IB(ResultBytes.data(), ResultBytes.size());
RetT ReturnValue;
if (!RetDeserialization::deserialize(IB, ReturnValue))
@@ -58,6 +60,20 @@ template <typename SPSSig> class SPSCallSerializer {
}
};
+/// SPS serialization for void calls.
+template <typename... SPSArgTs>
+struct SPSCallSerializer<void(SPSArgTs...)>
+ : public detail::SPSCallSerialization<void(SPSArgTs...)> {
+ template <typename RetT>
+ std::enable_if_t<std::is_void_v<RetT>, Error>
+ deserialize(shared::WrapperFunctionResult ResultBytes) {
+ if (!ResultBytes.empty())
+ return make_error<StringError>("Could not deserialize return value",
+ inconvertibleErrorCode());
+ return Error::success();
+ }
+};
+
template <typename SPSSig>
class SPSEPCCaller : public EPCCaller<SPSCallSerializer<SPSSig>> {
public:
diff --git a/llvm/include/llvm/ExecutionEngine/Orc/CallViaEPC.h b/llvm/include/llvm/ExecutionEngine/Orc/CallViaEPC.h
index 1ec422f9da716..b825d82e1d5fd 100644
--- a/llvm/include/llvm/ExecutionEngine/Orc/CallViaEPC.h
+++ b/llvm/include/llvm/ExecutionEngine/Orc/CallViaEPC.h
@@ -25,15 +25,33 @@ namespace llvm::orc {
namespace detail {
-// Helper to extract the Expected<T> argument type from a handler callable.
-template <typename HandlerT> struct HandlerTraits {
+template <typename HandlerArgT> struct CallViaEPCRetValueTraits;
+
+template <typename RetT> struct CallViaEPCRetValueTraits<Expected<RetT>> {
+ using value_type = RetT;
+};
+
+template <> struct CallViaEPCRetValueTraits<Error> {
+ using value_type = void;
+};
+
+template <typename RetT> struct CallViaEPCRetValueTraits<MSVCPExpected<RetT>> {
+ using value_type = RetT;
+};
+
+template <> struct CallViaEPCRetValueTraits<MSVCPError> {
+ using value_type = void;
+};
+
+// Helper to extract the argument type from a handler callable.
+template <typename HandlerT> struct CallViaEPCHandlerTraits {
using ArgInfo = CallableArgInfo<HandlerT>;
using ArgsTuple = typename ArgInfo::ArgsTupleType;
static_assert(std::tuple_size_v<ArgsTuple> == 1,
"Handler must take exactly one argument");
- using ExpectedArgType = std::tuple_element_t<0, ArgsTuple>;
- using RetT = typename std::remove_cv_t<
- std::remove_reference_t<ExpectedArgType>>::value_type;
+ using HandlerArgT = std::tuple_element_t<0, ArgsTuple>;
+ using RetT = typename CallViaEPCRetValueTraits<
+ std::remove_cv_t<std::remove_reference_t<HandlerArgT>>>::value_type;
};
} // namespace detail
@@ -43,7 +61,7 @@ template <typename HandlerFn, typename Serializer, typename... ArgTs>
std::enable_if_t<std::is_invocable_v<HandlerFn, Error>>
callViaEPC(HandlerFn &&H, ExecutorProcessControl &EPC, Serializer S,
ExecutorSymbolDef Fn, ArgTs &&...Args) {
- using RetT = typename detail::HandlerTraits<HandlerFn>::RetT;
+ using RetT = typename detail::CallViaEPCHandlerTraits<HandlerFn>::RetT;
if (auto ArgBytes = S.serialize(std::forward<ArgTs>(Args)...))
EPC.callWrapperAsync(
diff --git a/llvm/unittests/ExecutionEngine/Orc/CallSPSViaEPCTest.cpp b/llvm/unittests/ExecutionEngine/Orc/CallSPSViaEPCTest.cpp
index 25764bbe0d7e1..7e3d468ac8552 100644
--- a/llvm/unittests/ExecutionEngine/Orc/CallSPSViaEPCTest.cpp
+++ b/llvm/unittests/ExecutionEngine/Orc/CallSPSViaEPCTest.cpp
@@ -19,6 +19,10 @@ using namespace llvm;
using namespace llvm::orc;
using namespace llvm::orc::shared;
+static CWrapperFunctionResult voidWrapper(const char *ArgData, size_t ArgSize) {
+ return WrapperFunction<void()>::handle(ArgData, ArgSize, []() {}).release();
+}
+
static CWrapperFunctionResult mainWrapper(const char *ArgData, size_t ArgSize) {
return WrapperFunction<int32_t(SPSSequence<SPSString>)>::handle(
ArgData, ArgSize,
@@ -28,6 +32,28 @@ static CWrapperFunctionResult mainWrapper(const char *ArgData, size_t ArgSize) {
.release();
}
+TEST(CallSPSViaEPCTest, CallVoidViaCallerAsync) {
+ auto EPC = cantFail(SelfExecutorProcessControl::Create());
+ SPSEPCCaller<void()> C(*EPC);
+
+ Error Err = Error::success();
+ {
+ ErrorAsOutParameter _(Err);
+ C([&](Error E) { Err = std::move(E); },
+ ExecutorSymbolDef::fromPtr(voidWrapper));
+ }
+ EXPECT_THAT_ERROR(std::move(Err), Succeeded());
+}
+
+TEST(CallSPSViaEPCTest, CallVoidViaCallerSync) {
+ auto EPC = cantFail(SelfExecutorProcessControl::Create());
+ SPSEPCCaller<void()> C(*EPC);
+
+ Error Err =
+ C(std::promise<MSVCPError>(), ExecutorSymbolDef::fromPtr(voidWrapper));
+ EXPECT_THAT_ERROR(std::move(Err), Succeeded());
+}
+
TEST(CallSPSViaEPCTest, CallMainViaCallerAsync) {
auto EPC = cantFail(SelfExecutorProcessControl::Create());
SPSEPCCaller<int32_t(SPSSequence<SPSString>)> C(*EPC);
More information about the llvm-commits
mailing list