[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