[libc-commits] [libc] [llvm] [libc] Rewrite libc GPU code to use rpc::dispatch where possible (PR #181727)
Joseph Huber via libc-commits
libc-commits at lists.llvm.org
Mon Feb 16 11:20:57 PST 2026
https://github.com/jhuber6 created https://github.com/llvm/llvm-project/pull/181727
Summary:
This uses the new `rpc::dispatch` support to simplify the usage in applicable
cases. There is one confusing part with the by-value handling of FILE pointers
and converting to handle the standard streams, but hopefully it's simple enough.
>From 521e3073b5648e297afc26a4d40d983af87cb79e Mon Sep 17 00:00:00 2001
From: Joseph Huber <huberjn at outlook.com>
Date: Fri, 13 Feb 2026 12:10:03 -0600
Subject: [PATCH 1/2] pick of https://github.com/llvm/llvm-project/pull/181395
test
Fix noexcept
Fix strict aliasing warnings
---
libc/shared/rpc_dispatch.h | 134 ++++++++++++++++-------------
libc/shared/rpc_util.h | 25 ++++++
offload/test/libc/rpc_callback.cpp | 22 +++++
3 files changed, 122 insertions(+), 59 deletions(-)
diff --git a/libc/shared/rpc_dispatch.h b/libc/shared/rpc_dispatch.h
index 1a385c1b7d82e..0bcb92515b223 100644
--- a/libc/shared/rpc_dispatch.h
+++ b/libc/shared/rpc_dispatch.h
@@ -51,47 +51,73 @@ template <typename... Ts> struct tuple_bytes {
template <typename... Ts>
struct tuple_bytes<rpc::tuple<Ts...>> : tuple_bytes<Ts...> {};
+// Whether a pointer value will be marshalled between the client and server.
+template <typename Ty, typename PtrTy = rpc::remove_reference_t<Ty>,
+ typename ElemTy = rpc::remove_pointer_t<PtrTy>>
+RPC_ATTRS constexpr bool is_marshalled_ptr_v =
+ rpc::is_pointer_v<PtrTy> && rpc::is_complete_v<ElemTy> &&
+ !rpc::is_void_v<ElemTy>;
+
+// Get an index value for the marshalled types in the tuple type.
+template <class Tuple, uint64_t... Is>
+constexpr uint64_t marshalled_index(rpc::index_sequence<Is...>) {
+ return (0u + ... +
+ (rpc::is_marshalled_ptr_v<rpc::tuple_element_t<Is, Tuple>>));
+}
+template <class Tuple, uint64_t I>
+constexpr uint64_t marshalled_index_v =
+ marshalled_index<Tuple>(rpc::make_index_sequence<I>{});
+
+// Storage for the marshalled arguments from the client.
+template <uint32_t NUM_LANES, typename... Ts> struct MarshalledState {
+ static constexpr uint32_t NUM_PTRS =
+ rpc::marshalled_index_v<rpc::tuple<Ts...>, sizeof...(Ts)>;
+
+ uint64_t sizes[NUM_PTRS][NUM_LANES]{};
+ void *ptrs[NUM_PTRS][NUM_LANES]{};
+};
+template <uint32_t NUM_LANES, typename... Ts>
+struct MarshalledState<NUM_LANES, rpc::tuple<Ts...>>
+ : MarshalledState<NUM_LANES, Ts...> {};
+
// Client-side dispatch of pointer values. We copy the memory associated with
// the pointer to the server and recieve back a server-side pointer to replace
// the client-side pointer in the argument list.
-template <uint64_t Idx, typename Tuple>
-RPC_ATTRS constexpr void prepare_arg(rpc::Client::Port &port, Tuple &t) {
+template <uint64_t Idx, typename Tuple, typename CallTuple>
+RPC_ATTRS constexpr void prepare_arg(rpc::Client::Port &port, Tuple &t,
+ CallTuple &ct) {
using ArgTy = rpc::tuple_element_t<Idx, Tuple>;
- using ElemTy = rpc::remove_pointer_t<ArgTy>;
- if constexpr (rpc::is_pointer_v<ArgTy> && rpc::is_complete_v<ElemTy> &&
- !rpc::is_void_v<ElemTy>) {
+ using CallArgTy = rpc::tuple_element_t<Idx, CallTuple>;
+ if constexpr (rpc::is_marshalled_ptr_v<ArgTy>) {
// We assume all constant character arrays are C-strings.
uint64_t size{};
if constexpr (rpc::is_same_v<ArgTy, const char *>)
size = rpc::string_length(rpc::get<Idx>(t));
+ else if constexpr (rpc::is_array_ref_v<CallArgTy>)
+ size = rpc::get<Idx>(ct).size * sizeof(rpc::remove_pointer_t<ArgTy>);
else
size = sizeof(rpc::remove_pointer_t<ArgTy>);
port.send_n(rpc::get<Idx>(t), size);
port.recv([&](rpc::Buffer *buffer, uint32_t) {
- rpc::get<Idx>(t) = *reinterpret_cast<ArgTy *>(buffer->data);
+ ArgTy val;
+ rpc::rpc_memcpy(&val, buffer->data, sizeof(ArgTy));
+ rpc::get<Idx>(t) = val;
});
}
}
// Server-side handling of pointer arguments. We recieve the memory into a
// temporary buffer and pass a pointer to this new memory back to the client.
-template <uint32_t NUM_LANES, typename Tuple, uint64_t Idx>
-RPC_ATTRS constexpr void prepare_arg(rpc::Server::Port &port) {
+template <uint32_t NUM_LANES, typename Tuple, uint64_t Idx, typename State>
+RPC_ATTRS constexpr void prepare_arg(rpc::Server::Port &port, State &&state) {
using ArgTy = rpc::tuple_element_t<Idx, Tuple>;
- using ElemTy = rpc::remove_pointer_t<ArgTy>;
- if constexpr (rpc::is_pointer_v<ArgTy> && rpc::is_complete_v<ElemTy> &&
- !rpc::is_void_v<ElemTy>) {
- void *args[NUM_LANES]{};
- uint64_t sizes[NUM_LANES]{};
- port.recv_n(args, sizes, [](uint64_t size) {
- if constexpr (rpc::is_same_v<ArgTy, const char *>)
- return malloc(size);
- else
- return malloc(
- sizeof(rpc::remove_const_t<rpc::remove_pointer_t<ArgTy>>));
- });
+ if constexpr (rpc::is_marshalled_ptr_v<ArgTy>) {
+ auto &ptrs = state.ptrs[rpc::marshalled_index_v<Tuple, Idx>];
+ auto &sizes = state.sizes[rpc::marshalled_index_v<Tuple, Idx>];
+ port.recv_n(ptrs, sizes, [](uint64_t size) { return malloc(size); });
port.send([&](rpc::Buffer *buffer, uint32_t id) {
- *reinterpret_cast<ArgTy *>(buffer->data) = static_cast<ArgTy>(args[id]);
+ ArgTy val = static_cast<ArgTy>(ptrs[id]);
+ rpc::rpc_memcpy(buffer->data, &val, sizeof(ArgTy));
});
}
}
@@ -102,14 +128,11 @@ RPC_ATTRS constexpr void prepare_arg(rpc::Server::Port &port) {
template <uint64_t Idx, typename Tuple>
RPC_ATTRS constexpr void finish_arg(rpc::Client::Port &port, Tuple &t) {
using ArgTy = rpc::tuple_element_t<Idx, Tuple>;
- using ElemTy = rpc::remove_pointer_t<ArgTy>;
- using MemoryTy = rpc::remove_const_t<rpc::remove_pointer_t<ArgTy>> *;
- if constexpr (rpc::is_pointer_v<ArgTy> && !rpc::is_const_v<ArgTy> &&
- rpc::is_complete_v<ElemTy> && !rpc::is_void_v<ElemTy>) {
+ if constexpr (rpc::is_marshalled_ptr_v<ArgTy> && !rpc::is_const_v<ArgTy>) {
uint64_t size{};
void *buf{};
port.recv_n(&buf, &size, [&](uint64_t) {
- return const_cast<MemoryTy>(rpc::get<Idx>(t));
+ return const_cast<void *>(static_cast<const void *>(rpc::get<Idx>(t)));
});
}
}
@@ -117,30 +140,20 @@ RPC_ATTRS constexpr void finish_arg(rpc::Client::Port &port, Tuple &t) {
// Server-side finalization of pointer arguments. We copy any potential
// modifications to the value back to the client unless it was a constant. We
// can also free the associated memory.
-template <uint32_t NUM_LANES, uint64_t Idx, typename Tuple>
-RPC_ATTRS constexpr void finish_arg(rpc::Server::Port &port,
- Tuple (&t)[NUM_LANES]) {
+template <uint32_t NUM_LANES, typename Tuple, uint64_t Idx, typename State>
+RPC_ATTRS constexpr void finish_arg(rpc::Server::Port &port, State &&state) {
using ArgTy = rpc::tuple_element_t<Idx, Tuple>;
- using ElemTy = rpc::remove_pointer_t<ArgTy>;
- if constexpr (rpc::is_pointer_v<ArgTy> && !rpc::is_const_v<ArgTy> &&
- rpc::is_complete_v<ElemTy> && !rpc::is_void_v<ElemTy>) {
- const void *buffer[NUM_LANES]{};
- size_t sizes[NUM_LANES]{};
- for (uint32_t id = 0; id < NUM_LANES; ++id) {
- if (port.get_lane_mask() & (uint64_t(1) << id)) {
- buffer[id] = rpc::get<Idx>(t[id]);
- sizes[id] = sizeof(rpc::remove_pointer_t<ArgTy>);
- }
- }
- port.send_n(buffer, sizes);
+ if constexpr (rpc::is_marshalled_ptr_v<ArgTy> && !rpc::is_const_v<ArgTy>) {
+ auto &ptrs = state.ptrs[rpc::marshalled_index_v<Tuple, Idx>];
+ auto &sizes = state.sizes[rpc::marshalled_index_v<Tuple, Idx>];
+ port.send_n(ptrs, sizes);
}
- if constexpr (rpc::is_pointer_v<ArgTy> && rpc::is_complete_v<ElemTy> &&
- !rpc::is_void_v<ElemTy>) {
+ if constexpr (rpc::is_marshalled_ptr_v<ArgTy>) {
+ auto &ptrs = state.ptrs[rpc::marshalled_index_v<Tuple, Idx>];
for (uint32_t id = 0; id < NUM_LANES; ++id) {
if (port.get_lane_mask() & (uint64_t(1) << id))
- free(const_cast<void *>(
- static_cast<const void *>(rpc::get<Idx>(t[id]))));
+ free(const_cast<void *>(static_cast<const void *>(ptrs[id])));
}
}
}
@@ -148,15 +161,16 @@ RPC_ATTRS constexpr void finish_arg(rpc::Server::Port &port,
// Iterate over the tuple list of arguments to see if we need to forward any.
// The current forwarding is somewhat inefficient as each pointer is an
// individual RPC call.
-template <typename Tuple, uint64_t... Is>
+template <typename Tuple, typename CallTuple, uint64_t... Is>
RPC_ATTRS constexpr void prepare_args(rpc::Client::Port &port, Tuple &t,
+ CallTuple &ct,
rpc::index_sequence<Is...>) {
- (prepare_arg<Is>(port, t), ...);
+ (prepare_arg<Is>(port, t, ct), ...);
}
-template <uint32_t NUM_LANES, typename Tuple, uint64_t... Is>
-RPC_ATTRS constexpr void prepare_args(rpc::Server::Port &port,
+template <uint32_t NUM_LANES, typename Tuple, typename State, uint64_t... Is>
+RPC_ATTRS constexpr void prepare_args(rpc::Server::Port &port, State &&state,
rpc::index_sequence<Is...>) {
- (prepare_arg<NUM_LANES, Tuple, Is>(port), ...);
+ (prepare_arg<NUM_LANES, Tuple, Is>(port, state), ...);
}
// Performs the preparation in reverse, copying back any modified values.
@@ -165,11 +179,10 @@ RPC_ATTRS constexpr void finish_args(rpc::Client::Port &port, Tuple &&t,
rpc::index_sequence<Is...>) {
(finish_arg<Is>(port, t), ...);
}
-template <uint32_t NUM_LANES, typename Tuple, uint64_t... Is>
-RPC_ATTRS constexpr void finish_args(rpc::Server::Port &port,
- Tuple (&t)[NUM_LANES],
+template <uint32_t NUM_LANES, typename Tuple, typename State, uint64_t... Is>
+RPC_ATTRS constexpr void finish_args(rpc::Server::Port &port, State &&state,
rpc::index_sequence<Is...>) {
- (finish_arg<NUM_LANES, Is>(port, t), ...);
+ (finish_arg<NUM_LANES, Tuple, Is>(port, state), ...);
}
} // namespace
@@ -181,7 +194,7 @@ dispatch(rpc::Client &client, FnTy, CallArgs... args) {
using Traits = function_traits<FnTy>;
using RetTy = typename Traits::return_type;
using TupleTy = typename Traits::arg_types;
- using Bytes = tuple_bytes<CallArgs...>;
+ using Bytes = tuple_bytes<rpc::remove_array_ref_t<CallArgs>...>;
static_assert(sizeof...(CallArgs) == Traits::ARITY,
"Argument count mismatch");
@@ -193,8 +206,10 @@ dispatch(rpc::Client &client, FnTy, CallArgs... args) {
auto port = client.open<OPCODE>();
// Copy over any pointer arguments by walking the argument list.
+ rpc::tuple<CallArgs...> call_args{args...};
TupleTy arg_tuple{rpc::forward<CallArgs>(args)...};
- rpc::prepare_args(port, arg_tuple, rpc::make_index_sequence<Traits::ARITY>{});
+ rpc::prepare_args(port, arg_tuple, call_args,
+ rpc::make_index_sequence<Traits::ARITY>{});
// Compress the argument list to a binary stream and send it to the server.
auto bytes = Bytes::pack(arg_tuple);
@@ -224,8 +239,9 @@ RPC_ATTRS constexpr void invoke(rpc::Server::Port &port, FnTy fn) {
using Bytes = tuple_bytes<TupleTy>;
// Recieve pointer data from the host and pack it in server-side memory.
+ MarshalledState<NUM_LANES, TupleTy> state{};
rpc::prepare_args<NUM_LANES, TupleTy>(
- port, rpc::make_index_sequence<Traits::ARITY>{});
+ port, state, rpc::make_index_sequence<Traits::ARITY>{});
// Get the argument list from the client.
typename Bytes::array_type arg_buf[NUM_LANES]{};
@@ -252,8 +268,8 @@ RPC_ATTRS constexpr void invoke(rpc::Server::Port &port, FnTy fn) {
}
// Send any potentially modified pointer arguments back to the client.
- rpc::finish_args<NUM_LANES>(port, args,
- rpc::make_index_sequence<Traits::ARITY>{});
+ rpc::finish_args<NUM_LANES, TupleTy>(
+ port, state, rpc::make_index_sequence<Traits::ARITY>{});
// Copy back the return value of the function if one exists. If the function
// is void we send an empty packet to force synchronous behavior.
diff --git a/libc/shared/rpc_util.h b/libc/shared/rpc_util.h
index 171caff1140f9..f641434aca2c0 100644
--- a/libc/shared/rpc_util.h
+++ b/libc/shared/rpc_util.h
@@ -106,6 +106,25 @@ template <typename T, typename... Args>
RPC_ATTRS constexpr bool is_trivially_constructible_v =
is_trivially_constructible<T>::value;
+/// Tag type to indicate an array of elements being passed through RPC.
+template <typename T> struct array_ref {
+ T *data;
+ uint64_t size;
+ RPC_ATTRS operator T *() const { return data; }
+};
+
+template <typename T> struct is_array_ref : type_constant<bool, false> {};
+template <typename T>
+struct is_array_ref<array_ref<T>> : type_constant<bool, true> {};
+template <typename T>
+RPC_ATTRS constexpr bool is_array_ref_v = is_array_ref<T>::value;
+
+template <typename T> struct remove_array_ref : type_identity<T> {};
+template <typename T>
+struct remove_array_ref<array_ref<T>> : type_identity<T *> {};
+template <typename T>
+using remove_array_ref_t = typename remove_array_ref<T>::type;
+
template <bool B, typename T, typename F>
struct conditional : type_identity<T> {};
template <typename T, typename F>
@@ -447,6 +466,12 @@ template <typename R, typename... Args> struct function_traits<R (*)(Args...)> {
using arg_types = rpc::tuple<Args...>;
static constexpr uint64_t ARITY = sizeof...(Args);
};
+template <typename R, typename... Args>
+struct function_traits<R (*)(Args...) noexcept> {
+ using return_type = R;
+ using arg_types = rpc::tuple<Args...>;
+ static constexpr uint64_t ARITY = sizeof...(Args);
+};
template <typename T> T &&declval();
template <typename T>
struct function_traits
diff --git a/offload/test/libc/rpc_callback.cpp b/offload/test/libc/rpc_callback.cpp
index f313541e58d1d..3502faccb64b4 100644
--- a/offload/test/libc/rpc_callback.cpp
+++ b/offload/test/libc/rpc_callback.cpp
@@ -32,6 +32,7 @@ constexpr uint32_t CONST_PTR_OPCODE = 4;
constexpr uint32_t STRING_OPCODE = 5;
constexpr uint32_t EMPTY_OPCODE = 6;
constexpr uint32_t DIVERGENT_OPCODE = 7;
+constexpr uint32_t ARRAY_SUM_OPCODE = 8;
//===------------------------------------------------------------------------===
// Server-side implementations.
@@ -82,6 +83,14 @@ void divergent(int *p) {
*p = *p;
}
+// 8. Array argument via array_ref.
+int sum_array(const int *arr, int n) {
+ int s = 0;
+ for (int i = 0; i < n; ++i)
+ s += arr[i];
+ return s;
+}
+
//===------------------------------------------------------------------------===
// RPC client dispatch.
//===------------------------------------------------------------------------===
@@ -110,6 +119,11 @@ int empty() { return rpc::dispatch<EMPTY_OPCODE>(client, empty); }
void divergent(int *p) {
rpc::dispatch<DIVERGENT_OPCODE>(client, divergent, p);
}
+
+int sum_array(const int *arr, int n) {
+ return rpc::dispatch<ARRAY_SUM_OPCODE>(
+ client, sum_array, rpc::array_ref<const int>{arr, uint64_t(n)}, n);
+}
#pragma omp end declare variant
//===------------------------------------------------------------------------===
@@ -143,6 +157,9 @@ rpc::Status handleOpcodesImpl(rpc::Server::Port &Port) {
*p = *p;
});
break;
+ case ARRAY_SUM_OPCODE:
+ rpc::invoke<NUM_LANES>(Port, sum_array);
+ break;
default:
return rpc::RPC_UNHANDLED_OPCODE;
}
@@ -203,6 +220,11 @@ int main() {
if (id % 2)
divergent(&id);
assert(id == omp_get_thread_num());
+
+ // 8. Array sum via array_ref.
+ int arr[4] = {1, 2, 3, 4};
+ int total = sum_array(arr, 4);
+ assert(total == 10);
}
printf("PASS\n");
>From dc63392e61beb7428c084a0211921072de26698d Mon Sep 17 00:00:00 2001
From: Joseph Huber <huberjn at outlook.com>
Date: Mon, 16 Feb 2026 11:46:21 -0600
Subject: [PATCH 2/2] [libc] Rewrite RPC wrappers to use dispatch internally
---
libc/src/__support/RPC/rpc_client.h | 3 +
libc/src/__support/RPC/rpc_server.h | 99 ++++++-------------
libc/src/stdio/gpu/clearerr.cpp | 10 +-
libc/src/stdio/gpu/fclose.cpp | 12 +--
libc/src/stdio/gpu/feof.cpp | 13 +--
libc/src/stdio/gpu/ferror.cpp | 14 +--
libc/src/stdio/gpu/fflush.cpp | 14 +--
libc/src/stdio/gpu/fgets.cpp | 18 +---
libc/src/stdio/gpu/fopen.cpp | 12 +--
libc/src/stdio/gpu/fseek.cpp | 16 +--
libc/src/stdio/gpu/ftell.cpp | 14 +--
libc/src/stdio/gpu/remove.cpp | 13 +--
libc/src/stdio/gpu/rename.cpp | 15 +--
libc/src/stdio/gpu/ungetc.cpp | 15 +--
libc/src/stdlib/gpu/system.cpp | 15 +--
.../startup/gpu/rpc_stream_test.cpp | 2 +-
16 files changed, 66 insertions(+), 219 deletions(-)
diff --git a/libc/src/__support/RPC/rpc_client.h b/libc/src/__support/RPC/rpc_client.h
index 199803badf1a9..1b5c56412bbbe 100644
--- a/libc/src/__support/RPC/rpc_client.h
+++ b/libc/src/__support/RPC/rpc_client.h
@@ -10,6 +10,7 @@
#define LLVM_LIBC_SRC___SUPPORT_RPC_RPC_CLIENT_H
#include "shared/rpc.h"
+#include "shared/rpc_dispatch.h"
#include "shared/rpc_opcodes.h"
#include "src/__support/CPP/type_traits.h"
@@ -23,6 +24,8 @@ using ::rpc::Client;
using ::rpc::Port;
using ::rpc::Process;
using ::rpc::Server;
+using ::rpc::dispatch;
+using ::rpc::array_ref;
static_assert(cpp::is_trivially_copyable<Client>::value &&
sizeof(Process<true>) == sizeof(Process<false>),
diff --git a/libc/src/__support/RPC/rpc_server.h b/libc/src/__support/RPC/rpc_server.h
index d06700a787e94..7712521b7ac81 100644
--- a/libc/src/__support/RPC/rpc_server.h
+++ b/libc/src/__support/RPC/rpc_server.h
@@ -41,6 +41,7 @@
#define LIBC_TYPES_LONG_DOUBLE_IS_FLOAT64
#include "shared/rpc.h"
+#include "shared/rpc_dispatch.h"
#include "shared/rpc_opcodes.h"
#include "src/__support/arg_list.h"
@@ -352,35 +353,20 @@ LIBC_INLINE static rpc::Status handle_port_impl(rpc::Server::Port &port) {
break;
}
case LIBC_READ_FGETS: {
- uint64_t sizes[num_lanes] = {0};
- void *data[num_lanes] = {nullptr};
- port.recv([&](rpc::Buffer *buffer, uint32_t id) {
- data[id] = temp_storage.alloc(buffer->data[0]);
- const char *str = ::fgets(reinterpret_cast<char *>(data[id]),
- static_cast<int>(buffer->data[0]),
- to_stream(buffer->data[1]));
- sizes[id] = !str ? 0 : __builtin_strlen(str) + 1;
- });
- port.send_n(data, sizes);
+ rpc::invoke<num_lanes>(
+ port, [](char *str, int count, void *stream) -> char * {
+ return ::fgets(str, count,
+ to_stream(reinterpret_cast<uintptr_t>(stream)));
+ });
break;
}
case LIBC_OPEN_FILE: {
- uint64_t sizes[num_lanes] = {0};
- void *paths[num_lanes] = {nullptr};
- port.recv_n(paths, sizes,
- [&](uint64_t size) { return temp_storage.alloc(size); });
- port.recv_and_send([&](rpc::Buffer *buffer, uint32_t id) {
- FILE *file = fopen(reinterpret_cast<char *>(paths[id]),
- reinterpret_cast<char *>(buffer->data));
- buffer->data[0] = reinterpret_cast<uintptr_t>(file);
- });
+ rpc::invoke<num_lanes>(port, fopen);
break;
}
case LIBC_CLOSE_FILE: {
- port.recv_and_send([&](rpc::Buffer *buffer, uint32_t) {
- FILE *file = reinterpret_cast<FILE *>(buffer->data[0]);
- buffer->data[0] = ::fclose(file);
- });
+ rpc::invoke<num_lanes>(
+ port, [](void *f) -> int { return ::fclose(static_cast<FILE *>(f)); });
break;
}
case LIBC_EXIT: {
@@ -419,47 +405,46 @@ LIBC_INLINE static rpc::Status handle_port_impl(rpc::Server::Port &port) {
break;
}
case LIBC_FEOF: {
- port.recv_and_send([](rpc::Buffer *buffer, uint32_t) {
- buffer->data[0] = feof(to_stream(buffer->data[0]));
+ rpc::invoke<num_lanes>(port, [](void *stream) -> int {
+ return feof(to_stream(reinterpret_cast<uintptr_t>(stream)));
});
break;
}
case LIBC_FERROR: {
- port.recv_and_send([](rpc::Buffer *buffer, uint32_t) {
- buffer->data[0] = ferror(to_stream(buffer->data[0]));
+ rpc::invoke<num_lanes>(port, [](void *stream) -> int {
+ return ferror(to_stream(reinterpret_cast<uintptr_t>(stream)));
});
break;
}
case LIBC_CLEARERR: {
- port.recv_and_send([](rpc::Buffer *buffer, uint32_t) {
- clearerr(to_stream(buffer->data[0]));
+ rpc::invoke<num_lanes>(port, [](void *stream) {
+ clearerr(to_stream(reinterpret_cast<uintptr_t>(stream)));
});
break;
}
case LIBC_FSEEK: {
- port.recv_and_send([](rpc::Buffer *buffer, uint32_t) {
- buffer->data[0] =
- fseek(to_stream(buffer->data[0]), static_cast<long>(buffer->data[1]),
- static_cast<int>(buffer->data[2]));
- });
+ rpc::invoke<num_lanes>(
+ port, [](void *stream, long offset, int whence) -> int {
+ return fseek(to_stream(reinterpret_cast<uintptr_t>(stream)), offset,
+ whence);
+ });
break;
}
case LIBC_FTELL: {
- port.recv_and_send([](rpc::Buffer *buffer, uint32_t) {
- buffer->data[0] = ftell(to_stream(buffer->data[0]));
+ rpc::invoke<num_lanes>(port, [](void *stream) -> long {
+ return ftell(to_stream(reinterpret_cast<uintptr_t>(stream)));
});
break;
}
case LIBC_FFLUSH: {
- port.recv_and_send([](rpc::Buffer *buffer, uint32_t) {
- buffer->data[0] = fflush(to_stream(buffer->data[0]));
+ rpc::invoke<num_lanes>(port, [](void *stream) -> int {
+ return fflush(to_stream(reinterpret_cast<uintptr_t>(stream)));
});
break;
}
case LIBC_UNGETC: {
- port.recv_and_send([](rpc::Buffer *buffer, uint32_t) {
- buffer->data[0] =
- ungetc(static_cast<int>(buffer->data[0]), to_stream(buffer->data[1]));
+ rpc::invoke<num_lanes>(port, [](int c, void *stream) -> int {
+ return ungetc(c, to_stream(reinterpret_cast<uintptr_t>(stream)));
});
break;
}
@@ -476,41 +461,15 @@ LIBC_INLINE static rpc::Status handle_port_impl(rpc::Server::Port &port) {
break;
}
case LIBC_REMOVE: {
- uint64_t sizes[num_lanes] = {0};
- void *args[num_lanes] = {nullptr};
- port.recv_n(args, sizes,
- [&](uint64_t size) { return temp_storage.alloc(size); });
- port.send([&](rpc::Buffer *buffer, uint32_t id) {
- buffer->data[0] = static_cast<uint64_t>(
- remove(reinterpret_cast<const char *>(args[id])));
- });
+ rpc::invoke<num_lanes>(port, remove);
break;
}
case LIBC_RENAME: {
- uint64_t oldsizes[num_lanes] = {0};
- uint64_t newsizes[num_lanes] = {0};
- void *oldpath[num_lanes] = {nullptr};
- void *newpath[num_lanes] = {nullptr};
- port.recv_n(oldpath, oldsizes,
- [&](uint64_t size) { return temp_storage.alloc(size); });
- port.recv_n(newpath, newsizes,
- [&](uint64_t size) { return temp_storage.alloc(size); });
- port.send([&](rpc::Buffer *buffer, uint32_t id) {
- buffer->data[0] = static_cast<uint64_t>(
- rename(reinterpret_cast<const char *>(oldpath[id]),
- reinterpret_cast<const char *>(newpath[id])));
- });
+ rpc::invoke<num_lanes>(port, rename);
break;
}
case LIBC_SYSTEM: {
- uint64_t sizes[num_lanes] = {0};
- void *args[num_lanes] = {nullptr};
- port.recv_n(args, sizes,
- [&](uint64_t size) { return temp_storage.alloc(size); });
- port.send([&](rpc::Buffer *buffer, uint32_t id) {
- buffer->data[0] = static_cast<uint64_t>(
- system(reinterpret_cast<const char *>(args[id])));
- });
+ rpc::invoke<num_lanes>(port, system);
break;
}
case LIBC_TEST_INCREMENT: {
diff --git a/libc/src/stdio/gpu/clearerr.cpp b/libc/src/stdio/gpu/clearerr.cpp
index 5a0ca52e33fa0..c98c6ccbdac17 100644
--- a/libc/src/stdio/gpu/clearerr.cpp
+++ b/libc/src/stdio/gpu/clearerr.cpp
@@ -15,13 +15,9 @@
namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(void, clearerr, (::FILE * stream)) {
- rpc::Client::Port port = rpc::client.open<LIBC_CLEARERR>();
- port.send_and_recv(
- [=](rpc::Buffer *buffer, uint32_t) {
- buffer->data[0] = file::from_stream(stream);
- },
- [&](rpc::Buffer *, uint32_t) {});
- port.close();
+ rpc::dispatch<LIBC_CLEARERR>(
+ rpc::client, clearerr,
+ reinterpret_cast<FILE *>(file::from_stream(stream)));
}
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdio/gpu/fclose.cpp b/libc/src/stdio/gpu/fclose.cpp
index 1e00515e0650b..b69611035fc37 100644
--- a/libc/src/stdio/gpu/fclose.cpp
+++ b/libc/src/stdio/gpu/fclose.cpp
@@ -16,17 +16,7 @@
namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(int, fclose, (::FILE * stream)) {
- uint64_t ret = 0;
- uintptr_t file = reinterpret_cast<uintptr_t>(stream);
- rpc::Client::Port port = rpc::client.open<LIBC_CLOSE_FILE>();
- port.send_and_recv(
- [=](rpc::Buffer *buffer, uint32_t) { buffer->data[0] = file; },
- [&](rpc::Buffer *buffer, uint32_t) { ret = buffer->data[0]; });
- port.close();
-
- if (ret != 0)
- return EOF;
- return static_cast<int>(ret);
+ return rpc::dispatch<LIBC_CLOSE_FILE>(rpc::client, fclose, stream);
}
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdio/gpu/feof.cpp b/libc/src/stdio/gpu/feof.cpp
index 3ae308bad60b2..ff30ac7a75bc0 100644
--- a/libc/src/stdio/gpu/feof.cpp
+++ b/libc/src/stdio/gpu/feof.cpp
@@ -15,17 +15,8 @@
namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(int, feof, (::FILE * stream)) {
- int ret;
- rpc::Client::Port port = rpc::client.open<LIBC_FEOF>();
- port.send_and_recv(
- [=](rpc::Buffer *buffer, uint32_t) {
- buffer->data[0] = file::from_stream(stream);
- },
- [&](rpc::Buffer *buffer, uint32_t) {
- ret = static_cast<int>(buffer->data[0]);
- });
- port.close();
- return ret;
+ return rpc::dispatch<LIBC_FEOF>(
+ rpc::client, feof, reinterpret_cast<FILE *>(file::from_stream(stream)));
}
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdio/gpu/ferror.cpp b/libc/src/stdio/gpu/ferror.cpp
index 64d62e7065258..c009bfc336992 100644
--- a/libc/src/stdio/gpu/ferror.cpp
+++ b/libc/src/stdio/gpu/ferror.cpp
@@ -15,17 +15,9 @@
namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(int, ferror, (::FILE * stream)) {
- int ret;
- rpc::Client::Port port = rpc::client.open<LIBC_FERROR>();
- port.send_and_recv(
- [=](rpc::Buffer *buffer, uint32_t) {
- buffer->data[0] = file::from_stream(stream);
- },
- [&](rpc::Buffer *buffer, uint32_t) {
- ret = static_cast<int>(buffer->data[0]);
- });
- port.close();
- return ret;
+ return rpc::dispatch<LIBC_FERROR>(
+ rpc::client, ferror,
+ reinterpret_cast<FILE *>(file::from_stream(stream)));
}
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdio/gpu/fflush.cpp b/libc/src/stdio/gpu/fflush.cpp
index 0b6ef92f346af..056d63cd3d61e 100644
--- a/libc/src/stdio/gpu/fflush.cpp
+++ b/libc/src/stdio/gpu/fflush.cpp
@@ -15,17 +15,9 @@
namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(int, fflush, (::FILE * stream)) {
- int ret;
- rpc::Client::Port port = rpc::client.open<LIBC_FFLUSH>();
- port.send_and_recv(
- [=](rpc::Buffer *buffer, uint32_t) {
- buffer->data[0] = file::from_stream(stream);
- },
- [&](rpc::Buffer *buffer, uint32_t) {
- ret = static_cast<int>(buffer->data[0]);
- });
- port.close();
- return ret;
+ return rpc::dispatch<LIBC_FFLUSH>(
+ rpc::client, fflush,
+ reinterpret_cast<FILE *>(file::from_stream(stream)));
}
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdio/gpu/fgets.cpp b/libc/src/stdio/gpu/fgets.cpp
index e1c6088b60088..1b2fef4ede5b8 100644
--- a/libc/src/stdio/gpu/fgets.cpp
+++ b/libc/src/stdio/gpu/fgets.cpp
@@ -22,21 +22,11 @@ LLVM_LIBC_FUNCTION(char *, fgets,
if (count < 1)
return nullptr;
- uint64_t recv_size;
- void *buf = nullptr;
- rpc::Client::Port port = rpc::client.open<LIBC_READ_FGETS>();
- port.send([=](rpc::Buffer *buffer, uint32_t) {
- buffer->data[0] = count;
- buffer->data[1] = file::from_stream(stream);
- });
- port.recv_n(&buf, &recv_size,
- [&](uint64_t) { return reinterpret_cast<void *>(str); });
- port.close();
+ char *ret = rpc::dispatch<LIBC_READ_FGETS>(
+ rpc::client, fgets, rpc::array_ref<char>{str, uint64_t(count)}, count,
+ reinterpret_cast<FILE *>(file::from_stream(stream)));
- if (recv_size == 0)
- return nullptr;
-
- return str;
+ return ret ? str : nullptr;
}
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdio/gpu/fopen.cpp b/libc/src/stdio/gpu/fopen.cpp
index eee3edaac1c13..66e638e928482 100644
--- a/libc/src/stdio/gpu/fopen.cpp
+++ b/libc/src/stdio/gpu/fopen.cpp
@@ -18,17 +18,7 @@ namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(::FILE *, fopen,
(const char *__restrict path, const char *__restrict mode)) {
- uintptr_t file;
- rpc::Client::Port port = rpc::client.open<LIBC_OPEN_FILE>();
- port.send_n(path, internal::string_length(path) + 1);
- port.send_and_recv(
- [=](rpc::Buffer *buffer, uint32_t) {
- inline_memcpy(buffer->data, mode, internal::string_length(mode) + 1);
- },
- [&](rpc::Buffer *buffer, uint32_t) { file = buffer->data[0]; });
- port.close();
-
- return reinterpret_cast<FILE *>(file);
+ return rpc::dispatch<LIBC_OPEN_FILE>(rpc::client, fopen, path, mode);
}
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdio/gpu/fseek.cpp b/libc/src/stdio/gpu/fseek.cpp
index 468d65ff77e2a..4596d04a00483 100644
--- a/libc/src/stdio/gpu/fseek.cpp
+++ b/libc/src/stdio/gpu/fseek.cpp
@@ -15,19 +15,9 @@
namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(int, fseek, (::FILE * stream, long offset, int whence)) {
- int ret;
- rpc::Client::Port port = rpc::client.open<LIBC_FSEEK>();
- port.send_and_recv(
- [=](rpc::Buffer *buffer, uint32_t) {
- buffer->data[0] = file::from_stream(stream);
- buffer->data[1] = static_cast<uint64_t>(offset);
- buffer->data[2] = static_cast<uint64_t>(whence);
- },
- [&](rpc::Buffer *buffer, uint32_t) {
- ret = static_cast<int>(buffer->data[0]);
- });
- port.close();
- return ret;
+ return rpc::dispatch<LIBC_FSEEK>(
+ rpc::client, fseek,
+ reinterpret_cast<FILE *>(file::from_stream(stream)), offset, whence);
}
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdio/gpu/ftell.cpp b/libc/src/stdio/gpu/ftell.cpp
index 7ee33d7b05d9c..459b7e5aeaaf4 100644
--- a/libc/src/stdio/gpu/ftell.cpp
+++ b/libc/src/stdio/gpu/ftell.cpp
@@ -15,17 +15,9 @@
namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(long, ftell, (::FILE * stream)) {
- long ret;
- rpc::Client::Port port = rpc::client.open<LIBC_FSEEK>();
- port.send_and_recv(
- [=](rpc::Buffer *buffer, uint32_t) {
- buffer->data[0] = file::from_stream(stream);
- },
- [&](rpc::Buffer *buffer, uint32_t) {
- ret = static_cast<long>(buffer->data[0]);
- });
- port.close();
- return ret;
+ return rpc::dispatch<LIBC_FTELL>(
+ rpc::client, ftell,
+ reinterpret_cast<FILE *>(file::from_stream(stream)));
}
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdio/gpu/remove.cpp b/libc/src/stdio/gpu/remove.cpp
index 3cd72745cb6d3..1e80c94953cd9 100644
--- a/libc/src/stdio/gpu/remove.cpp
+++ b/libc/src/stdio/gpu/remove.cpp
@@ -8,22 +8,13 @@
#include "src/stdio/remove.h"
-#include "file.h"
-#include "hdr/types/FILE.h"
+#include "src/__support/RPC/rpc_client.h"
#include "src/__support/common.h"
-#include "src/string/string_utils.h"
namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(int, remove, (const char *path)) {
- int ret;
- rpc::Client::Port port = rpc::client.open<LIBC_REMOVE>();
- port.send_n(path, internal::string_length(path) + 1);
- port.recv([&](rpc::Buffer *buffer, uint32_t) {
- ret = static_cast<int>(buffer->data[0]);
- });
- port.close();
- return ret;
+ return rpc::dispatch<LIBC_REMOVE>(rpc::client, remove, path);
}
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdio/gpu/rename.cpp b/libc/src/stdio/gpu/rename.cpp
index d7c71fc826824..f2b4f06727e8f 100644
--- a/libc/src/stdio/gpu/rename.cpp
+++ b/libc/src/stdio/gpu/rename.cpp
@@ -8,24 +8,13 @@
#include "src/stdio/rename.h"
-#include "hdr/types/FILE.h"
+#include "src/__support/RPC/rpc_client.h"
#include "src/__support/common.h"
-#include "src/stdio/gpu/file.h"
-#include "src/string/string_utils.h"
namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(int, rename, (const char *oldpath, const char *newpath)) {
- int ret;
- rpc::Client::Port port = rpc::client.open<LIBC_RENAME>();
- port.send_n(oldpath, internal::string_length(oldpath) + 1);
- port.send_n(newpath, internal::string_length(newpath) + 1);
- port.recv([&](rpc::Buffer *buffer, uint32_t) {
- ret = static_cast<int>(buffer->data[0]);
- });
- port.close();
-
- return ret;
+ return rpc::dispatch<LIBC_RENAME>(rpc::client, rename, oldpath, newpath);
}
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdio/gpu/ungetc.cpp b/libc/src/stdio/gpu/ungetc.cpp
index fadd1d7db13cf..a9ce359804074 100644
--- a/libc/src/stdio/gpu/ungetc.cpp
+++ b/libc/src/stdio/gpu/ungetc.cpp
@@ -15,18 +15,9 @@
namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(int, ungetc, (int c, ::FILE *stream)) {
- int ret;
- rpc::Client::Port port = rpc::client.open<LIBC_UNGETC>();
- port.send_and_recv(
- [=](rpc::Buffer *buffer, uint32_t) {
- buffer->data[0] = c;
- buffer->data[1] = file::from_stream(stream);
- },
- [&](rpc::Buffer *buffer, uint32_t) {
- ret = static_cast<int>(buffer->data[0]);
- });
- port.close();
- return ret;
+ return rpc::dispatch<LIBC_UNGETC>(
+ rpc::client, ungetc, c,
+ reinterpret_cast<FILE *>(file::from_stream(stream)));
}
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdlib/gpu/system.cpp b/libc/src/stdlib/gpu/system.cpp
index 1677e6051c5fb..26681287b2c82 100644
--- a/libc/src/stdlib/gpu/system.cpp
+++ b/libc/src/stdlib/gpu/system.cpp
@@ -6,25 +6,16 @@
//
//===----------------------------------------------------------------------===//
+#include "src/stdlib/system.h"
+
#include "src/__support/RPC/rpc_client.h"
#include "src/__support/common.h"
#include "src/__support/macros/config.h"
-#include "src/string/string_utils.h"
-
-#include "src/stdlib/system.h"
namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(int, system, (const char *command)) {
- int ret;
- rpc::Client::Port port = rpc::client.open<LIBC_SYSTEM>();
- port.send_n(command, internal::string_length(command) + 1);
- port.recv([&](rpc::Buffer *buffer, uint32_t) {
- ret = static_cast<int>(buffer->data[0]);
- });
- port.close();
-
- return ret;
+ return rpc::dispatch<LIBC_SYSTEM>(rpc::client, system, command);
}
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/test/integration/startup/gpu/rpc_stream_test.cpp b/libc/test/integration/startup/gpu/rpc_stream_test.cpp
index b8c37926d2d42..bdbf300f27a74 100644
--- a/libc/test/integration/startup/gpu/rpc_stream_test.cpp
+++ b/libc/test/integration/startup/gpu/rpc_stream_test.cpp
@@ -15,7 +15,7 @@
#include "src/string/string_utils.h"
#include "test/IntegrationTest/test.h"
-extern "C" void *malloc(uint64_t);
+extern "C" void *malloc(size_t);
extern "C" void free(void *);
using namespace LIBC_NAMESPACE;
More information about the libc-commits
mailing list