[libc-commits] [libc] [llvm] [libc] Rewrite libc GPU code to use rpc::dispatch where possible (PR #181727)

via libc-commits libc-commits at lists.llvm.org
Mon Feb 16 11:21:29 PST 2026


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-offload

@llvm/pr-subscribers-libc

Author: Joseph Huber (jhuber6)

<details>
<summary>Changes</summary>

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.


---

Patch is 33.01 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/181727.diff


19 Files Affected:

- (modified) libc/shared/rpc_dispatch.h (+75-59) 
- (modified) libc/shared/rpc_util.h (+25) 
- (modified) libc/src/__support/RPC/rpc_client.h (+3) 
- (modified) libc/src/__support/RPC/rpc_server.h (+29-70) 
- (modified) libc/src/stdio/gpu/clearerr.cpp (+3-7) 
- (modified) libc/src/stdio/gpu/fclose.cpp (+1-11) 
- (modified) libc/src/stdio/gpu/feof.cpp (+2-11) 
- (modified) libc/src/stdio/gpu/ferror.cpp (+3-11) 
- (modified) libc/src/stdio/gpu/fflush.cpp (+3-11) 
- (modified) libc/src/stdio/gpu/fgets.cpp (+4-14) 
- (modified) libc/src/stdio/gpu/fopen.cpp (+1-11) 
- (modified) libc/src/stdio/gpu/fseek.cpp (+3-13) 
- (modified) libc/src/stdio/gpu/ftell.cpp (+3-11) 
- (modified) libc/src/stdio/gpu/remove.cpp (+2-11) 
- (modified) libc/src/stdio/gpu/rename.cpp (+2-13) 
- (modified) libc/src/stdio/gpu/ungetc.cpp (+3-12) 
- (modified) libc/src/stdlib/gpu/system.cpp (+3-12) 
- (modified) libc/test/integration/startup/gpu/rpc_stream_test.cpp (+1-1) 
- (modified) offload/test/libc/rpc_callback.cpp (+22) 


``````````diff
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/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_re...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/181727


More information about the libc-commits mailing list