[llvm] [orc-rt] Add initial call-function SPS CIs. (PR #202860)
Lang Hames via llvm-commits
llvm-commits at lists.llvm.org
Tue Jun 9 22:46:54 PDT 2026
https://github.com/lhames created https://github.com/llvm/llvm-project/pull/202860
Adds orc_rt_call_void_void and orc_rt_call_main, which can be used to call functions with `void(void)` and `int(int, char*[])` signatures, respectively.
>From 216e9280ccd94e8ba7879b3ae4b27c3d264896bd Mon Sep 17 00:00:00 2001
From: Lang Hames <lhames at gmail.com>
Date: Tue, 9 Jun 2026 22:51:17 +1000
Subject: [PATCH] [orc-rt] Add initial call-function SPS CIs.
Adds orc_rt_call_void_void and orc_rt_call_main, which can be used to call
functions with `void(void)` and `int(int, char*[])` signatures, respectively.
---
orc-rt/include/CMakeLists.txt | 1 +
orc-rt/include/orc-rt/sps-ci/CallSPSCI.h | 26 +++++
orc-rt/lib/executor/CMakeLists.txt | 1 +
orc-rt/lib/executor/sps-ci/CallSPSCI.cpp | 61 ++++++++++++
orc-rt/unittests/CMakeLists.txt | 1 +
orc-rt/unittests/CallSPSCITest.cpp | 116 +++++++++++++++++++++++
6 files changed, 206 insertions(+)
create mode 100644 orc-rt/include/orc-rt/sps-ci/CallSPSCI.h
create mode 100644 orc-rt/lib/executor/sps-ci/CallSPSCI.cpp
create mode 100644 orc-rt/unittests/CallSPSCITest.cpp
diff --git a/orc-rt/include/CMakeLists.txt b/orc-rt/include/CMakeLists.txt
index d1f60dd793c38..a8c9428696277 100644
--- a/orc-rt/include/CMakeLists.txt
+++ b/orc-rt/include/CMakeLists.txt
@@ -26,6 +26,7 @@ set(ORC_RT_HEADERS
orc-rt/SimplePackedSerialization.h
orc-rt/SPSAllocAction.h
orc-rt/sps-ci/AllSPSCI.h
+ orc-rt/sps-ci/CallSPSCI.h
orc-rt/sps-ci/MemoryAccessSPSCI.h
orc-rt/sps-ci/NativeDylibManagerSPSCI.h
orc-rt/sps-ci/SimpleNativeMemoryMapSPSCI.h
diff --git a/orc-rt/include/orc-rt/sps-ci/CallSPSCI.h b/orc-rt/include/orc-rt/sps-ci/CallSPSCI.h
new file mode 100644
index 0000000000000..550c7676f003a
--- /dev/null
+++ b/orc-rt/include/orc-rt/sps-ci/CallSPSCI.h
@@ -0,0 +1,26 @@
+//===------------ CallSPSCI.h - Function call SPS CI ------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// SPS Controller Interface registration for function callers.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef ORC_RT_SPS_CI_CALLSPSCI_H
+#define ORC_RT_SPS_CI_CALLSPSCI_H
+
+#include "orc-rt/SimpleSymbolTable.h"
+
+namespace orc_rt::sps_ci {
+
+/// Add the function callers SPS interface (orc_rt_ci_sps_call*) to the
+/// controller interface.
+Error addCall(SimpleSymbolTable &ST);
+
+} // namespace orc_rt::sps_ci
+
+#endif // ORC_RT_SPS_CI_CALLSPSCI_H
diff --git a/orc-rt/lib/executor/CMakeLists.txt b/orc-rt/lib/executor/CMakeLists.txt
index 6ef1ed79c6359..8a4168f354952 100644
--- a/orc-rt/lib/executor/CMakeLists.txt
+++ b/orc-rt/lib/executor/CMakeLists.txt
@@ -13,6 +13,7 @@ set(files
TaskDispatcher.cpp
ThreadPoolTaskDispatcher.cpp
sps-ci/AllSPSCI.cpp
+ sps-ci/CallSPSCI.cpp
sps-ci/MemoryAccessSPSCI.cpp
sps-ci/NativeDylibManagerSPSCI.cpp
sps-ci/SimpleNativeMemoryMapSPSCI.cpp
diff --git a/orc-rt/lib/executor/sps-ci/CallSPSCI.cpp b/orc-rt/lib/executor/sps-ci/CallSPSCI.cpp
new file mode 100644
index 0000000000000..16f8eb7f170cb
--- /dev/null
+++ b/orc-rt/lib/executor/sps-ci/CallSPSCI.cpp
@@ -0,0 +1,61 @@
+//===- CallSPSCI.cpp ------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// SPS Controller Interface registration for function callers.
+//
+//===----------------------------------------------------------------------===//
+
+#include "orc-rt/sps-ci/CallSPSCI.h"
+#include "orc-rt/SPSWrapperFunction.h"
+#include "orc-rt/move_only_function.h"
+
+#include <string>
+#include <vector>
+
+namespace orc_rt::sps_ci {
+
+using VoidVoidFn = void();
+
+void call_void_void(move_only_function<void()> Return, VoidVoidFn Fn) {
+ Fn();
+ Return();
+}
+
+ORC_RT_SPS_WRAPPER(orc_rt_ci_sps_call_void_void, void(SPSExecutorAddr),
+ call_void_void);
+
+using MainFn = int(int argc, char *argv[]);
+
+static std::vector<char *>
+makeNullTerminatedCStringArray(std::vector<std::string> &U) {
+ std::vector<char *> V;
+ V.reserve(U.size() + 1);
+ for (auto &E : U)
+ V.push_back(E.data());
+ V.push_back(nullptr);
+ return V;
+}
+
+void call_main(move_only_function<void(int64_t)> Return, MainFn Main,
+ std::vector<std::string> Args) {
+ auto ArgV = makeNullTerminatedCStringArray(Args);
+ Return(Main(ArgV.size(), ArgV.data()));
+}
+
+ORC_RT_SPS_WRAPPER(orc_rt_ci_sps_call_main,
+ int64_t(SPSExecutorAddr, SPSSequence<SPSString>), call_main);
+
+static std::pair<const char *, const void *> orc_rt_ci_sps_call_interface[] = {
+ ORC_RT_SYMTAB_PAIR(orc_rt_ci_sps_call_void_void),
+ ORC_RT_SYMTAB_PAIR(orc_rt_ci_sps_call_main)};
+
+Error addCall(SimpleSymbolTable &ST) {
+ return ST.addUnique(orc_rt_ci_sps_call_interface);
+}
+
+} // namespace orc_rt::sps_ci
diff --git a/orc-rt/unittests/CMakeLists.txt b/orc-rt/unittests/CMakeLists.txt
index 571e7f1444838..0bce4382f250f 100644
--- a/orc-rt/unittests/CMakeLists.txt
+++ b/orc-rt/unittests/CMakeLists.txt
@@ -15,6 +15,7 @@ add_orc_rt_unittest(CoreTests
AllocActionTest.cpp
BitmaskEnumTest.cpp
BootstrapInfoTest.cpp
+ CallSPSCITest.cpp
CallableTraitsHelperTest.cpp
SimpleSymbolTableTest.cpp
EndianTest.cpp
diff --git a/orc-rt/unittests/CallSPSCITest.cpp b/orc-rt/unittests/CallSPSCITest.cpp
new file mode 100644
index 0000000000000..b51e9ac87ab91
--- /dev/null
+++ b/orc-rt/unittests/CallSPSCITest.cpp
@@ -0,0 +1,116 @@
+//===- CallSPSCITest.cpp --------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Tests for the function-call SPS Controller Interface.
+//
+//===----------------------------------------------------------------------===//
+
+#include "orc-rt/sps-ci/CallSPSCI.h"
+#include "orc-rt/SPSWrapperFunction.h"
+
+#include "DirectCaller.h"
+#include "gtest/gtest.h"
+
+#include <optional>
+#include <string>
+#include <vector>
+
+using namespace orc_rt;
+
+namespace {
+
+class CallSPSCITest : public ::testing::Test {
+protected:
+ void SetUp() override { cantFail(sps_ci::addCall(CI)); }
+
+ DirectCaller caller(const char *Name) {
+ return DirectCaller(nullptr, reinterpret_cast<orc_rt_WrapperFunction>(
+ const_cast<void *>(CI.at(Name))));
+ }
+
+ SimpleSymbolTable CI;
+};
+
+TEST_F(CallSPSCITest, Registration) {
+ EXPECT_TRUE(CI.count("orc_rt_ci_sps_call_void_void"));
+ EXPECT_TRUE(CI.count("orc_rt_ci_sps_call_main"));
+}
+
+static int CallVoidVoidCount = 0;
+static void callVoidVoidFn() { ++CallVoidVoidCount; }
+
+TEST_F(CallSPSCITest, CallVoidVoid) {
+ using SPSSig = void(SPSExecutorAddr);
+ SPSWrapperFunction<SPSSig>::call(
+ caller("orc_rt_ci_sps_call_void_void"),
+ [](Error Err) { cantFail(std::move(Err)); },
+ reinterpret_cast<void *>(callVoidVoidFn));
+ EXPECT_EQ(CallVoidVoidCount, 1);
+}
+
+static int CallMainArgc = -1;
+static std::vector<std::string> CallMainArgv;
+static bool CallMainArgvIsNullTerminated = false;
+static int callMainFn(int Argc, char *Argv[]) {
+ CallMainArgc = Argc;
+ for (int I = 0; I < Argc; ++I)
+ CallMainArgv.emplace_back(Argv[I]);
+ // Per the C standard, argv[argc] shall be a null pointer.
+ CallMainArgvIsNullTerminated = (Argv[Argc] == nullptr);
+ return 42;
+}
+
+TEST_F(CallSPSCITest, CallMain) {
+ using SPSSig = int64_t(SPSExecutorAddr, SPSSequence<SPSString>);
+ std::optional<Expected<int64_t>> Result;
+ std::vector<std::string> Args = {"prog", "arg1", "arg2"};
+ SPSWrapperFunction<SPSSig>::call(
+ caller("orc_rt_ci_sps_call_main"),
+ [&](Expected<int64_t> R) { Result = std::move(R); },
+ reinterpret_cast<void *>(callMainFn), Args);
+
+ ASSERT_TRUE(Result.has_value());
+ ASSERT_TRUE(!!*Result) << toString(Result->takeError());
+ EXPECT_EQ(**Result, 42);
+
+ EXPECT_EQ(CallMainArgc, 3)
+ << "argc should equal the number of program arguments, "
+ "not including the null terminator";
+ ASSERT_EQ(CallMainArgv.size(), 3U);
+ EXPECT_EQ(CallMainArgv[0], "prog");
+ EXPECT_EQ(CallMainArgv[1], "arg1");
+ EXPECT_EQ(CallMainArgv[2], "arg2");
+ EXPECT_TRUE(CallMainArgvIsNullTerminated)
+ << "argv[argc] must be a null pointer per the C standard";
+}
+
+static int CallMainEmptyArgvArgc = -1;
+static bool CallMainEmptyArgvIsNullTerminated = false;
+static int callMainEmptyArgvFn(int Argc, char *Argv[]) {
+ CallMainEmptyArgvArgc = Argc;
+ CallMainEmptyArgvIsNullTerminated = (Argv[Argc] == nullptr);
+ return 42;
+}
+
+TEST_F(CallSPSCITest, CallMainEmptyArgv) {
+ using SPSSig = int64_t(SPSExecutorAddr, SPSSequence<SPSString>);
+ std::optional<Expected<int64_t>> Result;
+ std::vector<std::string> Args;
+ SPSWrapperFunction<SPSSig>::call(
+ caller("orc_rt_ci_sps_call_main"),
+ [&](Expected<int64_t> R) { Result = std::move(R); },
+ reinterpret_cast<void *>(callMainEmptyArgvFn), Args);
+
+ ASSERT_TRUE(Result.has_value());
+ ASSERT_TRUE(!!*Result) << toString(Result->takeError());
+ EXPECT_EQ(**Result, 42);
+ EXPECT_EQ(CallMainEmptyArgvArgc, 0);
+ EXPECT_TRUE(CallMainEmptyArgvIsNullTerminated);
+}
+
+} // namespace
More information about the llvm-commits
mailing list