Skip to content

Commit def22f4

Browse files
authored
[libc] Pull last dependencies into rpc_util.h (#116693)
Summary: Last bit in-place to remove the dependencies on LLVM libc headers. This just pulls the `sleep_briefly`, `std::optinal` and `type_traits` definitions into the `rpc_util.h` header. This duplicates some code for now but will soon be moved into the `include/rpc` directory. At that point I will remove all the `LIBC_INLINE` and just make it `RPC_INLINE`. Internal use will then have a wrapper to make it all LIBC namespaced, implementations will then implement their own handling.
1 parent c84a99d commit def22f4

File tree

3 files changed

+157
-13
lines changed

3 files changed

+157
-13
lines changed

libc/src/__support/RPC/rpc.h

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
#define LLVM_LIBC_SRC___SUPPORT_RPC_RPC_H
2020

2121
#include "rpc_util.h"
22-
#include "src/__support/CPP/optional.h"
22+
#include "src/__support/macros/attributes.h"
2323
#include "src/__support/macros/config.h"
2424

2525
#include <stdint.h>
@@ -306,7 +306,7 @@ template <bool T> struct Port {
306306

307307
friend struct Client;
308308
friend struct Server;
309-
friend class cpp::optional<Port<T>>;
309+
friend class rpc::optional<Port<T>>;
310310

311311
public:
312312
template <typename U> LIBC_INLINE void recv(U use);
@@ -362,9 +362,6 @@ struct Client {
362362
private:
363363
Process<false> process;
364364
};
365-
static_assert(cpp::is_trivially_copyable<Client>::value &&
366-
sizeof(Process<true>) == sizeof(Process<false>),
367-
"The client is not trivially copyable from the server");
368365

369366
/// The RPC server used to respond to the client.
370367
struct Server {
@@ -377,7 +374,7 @@ struct Server {
377374
: process(port_count, buffer) {}
378375

379376
using Port = rpc::Port<true>;
380-
LIBC_INLINE cpp::optional<Port> try_open(uint32_t lane_size,
377+
LIBC_INLINE rpc::optional<Port> try_open(uint32_t lane_size,
381378
uint32_t start = 0);
382379
LIBC_INLINE Port open(uint32_t lane_size);
383380

@@ -556,7 +553,7 @@ template <uint16_t opcode>
556553

557554
/// Attempts to open a port to use as the server. The server can only open a
558555
/// port if it has a pending receive operation
559-
[[clang::convergent]] LIBC_INLINE cpp::optional<typename Server::Port>
556+
[[clang::convergent]] LIBC_INLINE rpc::optional<typename Server::Port>
560557
Server::try_open(uint32_t lane_size, uint32_t start) {
561558
// Perform a naive linear scan for a port that has a pending request.
562559
for (uint32_t index = start; index < process.port_count; ++index) {
@@ -583,13 +580,13 @@ Server::try_open(uint32_t lane_size, uint32_t start) {
583580

584581
return Port(process, lane_mask, lane_size, index, out);
585582
}
586-
return cpp::nullopt;
583+
return rpc::nullopt;
587584
}
588585

589586
LIBC_INLINE Server::Port Server::open(uint32_t lane_size) {
590587
for (;;) {
591-
if (cpp::optional<Server::Port> p = try_open(lane_size))
592-
return cpp::move(p.value());
588+
if (rpc::optional<Server::Port> p = try_open(lane_size))
589+
return rpc::move(p.value());
593590
sleep_briefly();
594591
}
595592
}

libc/src/__support/RPC/rpc_client.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,16 @@
1212
#include "rpc.h"
1313

1414
#include "include/llvm-libc-types/rpc_opcodes_t.h"
15+
#include "src/__support/CPP/type_traits.h"
1516
#include "src/__support/macros/config.h"
1617

1718
namespace LIBC_NAMESPACE_DECL {
1819
namespace rpc {
1920

21+
static_assert(cpp::is_trivially_copyable<Client>::value &&
22+
sizeof(Process<true>) == sizeof(Process<false>),
23+
"The client is not trivially copyable from the server");
24+
2025
/// The libc client instance used to communicate with the server.
2126
extern Client client;
2227

libc/src/__support/RPC/rpc_util.h

Lines changed: 145 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,11 @@
99
#ifndef LLVM_LIBC_SRC___SUPPORT_RPC_RPC_UTIL_H
1010
#define LLVM_LIBC_SRC___SUPPORT_RPC_RPC_UTIL_H
1111

12-
#include "src/__support/CPP/type_traits.h"
12+
#include "src/__support/macros/attributes.h"
1313
#include "src/__support/macros/config.h"
14-
#include "src/__support/threads/sleep.h"
14+
15+
#include <stddef.h>
16+
#include <stdint.h>
1517

1618
#if defined(__NVPTX__) || defined(__AMDGPU__)
1719
#include <gpuintrin.h>
@@ -21,6 +23,146 @@
2123
namespace LIBC_NAMESPACE_DECL {
2224
namespace rpc {
2325

26+
template <typename T> struct type_identity {
27+
using type = T;
28+
};
29+
30+
template <class T, T v> struct type_constant {
31+
static inline constexpr T value = v;
32+
};
33+
34+
template <class T> struct remove_reference : type_identity<T> {};
35+
template <class T> struct remove_reference<T &> : type_identity<T> {};
36+
template <class T> struct remove_reference<T &&> : type_identity<T> {};
37+
38+
template <class T> struct is_const : type_constant<bool, false> {};
39+
template <class T> struct is_const<const T> : type_constant<bool, true> {};
40+
41+
/// Freestanding implementation of std::move.
42+
template <class T>
43+
LIBC_INLINE constexpr typename remove_reference<T>::type &&move(T &&t) {
44+
return static_cast<typename remove_reference<T>::type &&>(t);
45+
}
46+
47+
/// Freestanding implementation of std::forward.
48+
template <typename T>
49+
LIBC_INLINE constexpr T &&forward(typename remove_reference<T>::type &value) {
50+
return static_cast<T &&>(value);
51+
}
52+
template <typename T>
53+
LIBC_INLINE constexpr T &&forward(typename remove_reference<T>::type &&value) {
54+
return static_cast<T &&>(value);
55+
}
56+
57+
struct in_place_t {
58+
LIBC_INLINE explicit in_place_t() = default;
59+
};
60+
61+
struct nullopt_t {
62+
LIBC_INLINE constexpr explicit nullopt_t() = default;
63+
};
64+
65+
constexpr inline in_place_t in_place{};
66+
constexpr inline nullopt_t nullopt{};
67+
68+
/// Freestanding and minimal implementation of std::optional.
69+
template <typename T> class optional {
70+
template <typename U> struct OptionalStorage {
71+
union {
72+
char empty;
73+
U stored_value;
74+
};
75+
76+
bool in_use = false;
77+
78+
LIBC_INLINE ~OptionalStorage() { reset(); }
79+
80+
LIBC_INLINE constexpr OptionalStorage() : empty() {}
81+
82+
template <typename... Args>
83+
LIBC_INLINE constexpr explicit OptionalStorage(in_place_t, Args &&...args)
84+
: stored_value(forward<Args>(args)...) {}
85+
86+
LIBC_INLINE constexpr void reset() {
87+
if (in_use)
88+
stored_value.~U();
89+
in_use = false;
90+
}
91+
};
92+
93+
OptionalStorage<T> storage;
94+
95+
public:
96+
LIBC_INLINE constexpr optional() = default;
97+
LIBC_INLINE constexpr optional(nullopt_t) {}
98+
99+
LIBC_INLINE constexpr optional(const T &t) : storage(in_place, t) {
100+
storage.in_use = true;
101+
}
102+
LIBC_INLINE constexpr optional(const optional &) = default;
103+
104+
LIBC_INLINE constexpr optional(T &&t) : storage(in_place, move(t)) {
105+
storage.in_use = true;
106+
}
107+
LIBC_INLINE constexpr optional(optional &&O) = default;
108+
109+
LIBC_INLINE constexpr optional &operator=(T &&t) {
110+
storage = move(t);
111+
return *this;
112+
}
113+
LIBC_INLINE constexpr optional &operator=(optional &&) = default;
114+
115+
LIBC_INLINE constexpr optional &operator=(const T &t) {
116+
storage = t;
117+
return *this;
118+
}
119+
LIBC_INLINE constexpr optional &operator=(const optional &) = default;
120+
121+
LIBC_INLINE constexpr void reset() { storage.reset(); }
122+
123+
LIBC_INLINE constexpr const T &value() const & {
124+
return storage.stored_value;
125+
}
126+
127+
LIBC_INLINE constexpr T &value() & { return storage.stored_value; }
128+
129+
LIBC_INLINE constexpr explicit operator bool() const {
130+
return storage.in_use;
131+
}
132+
LIBC_INLINE constexpr bool has_value() const { return storage.in_use; }
133+
LIBC_INLINE constexpr const T *operator->() const {
134+
return &storage.stored_value;
135+
}
136+
LIBC_INLINE constexpr T *operator->() { return &storage.stored_value; }
137+
LIBC_INLINE constexpr const T &operator*() const & {
138+
return storage.stored_value;
139+
}
140+
LIBC_INLINE constexpr T &operator*() & { return storage.stored_value; }
141+
142+
LIBC_INLINE constexpr T &&value() && { return move(storage.stored_value); }
143+
LIBC_INLINE constexpr T &&operator*() && {
144+
return move(storage.stored_value);
145+
}
146+
};
147+
148+
/// Suspend the thread briefly to assist the thread scheduler during busy loops.
149+
LIBC_INLINE void sleep_briefly() {
150+
#if defined(LIBC_TARGET_ARCH_IS_NVPTX)
151+
if (__nvvm_reflect("__CUDA_ARCH") >= 700)
152+
asm("nanosleep.u32 64;" ::: "memory");
153+
#elif defined(LIBC_TARGET_ARCH_IS_AMDGPU)
154+
__builtin_amdgcn_s_sleep(2);
155+
#elif defined(LIBC_TARGET_ARCH_IS_X86)
156+
__builtin_ia32_pause();
157+
#elif defined(LIBC_TARGET_ARCH_IS_AARCH64) && __has_builtin(__builtin_arm_isb)
158+
__builtin_arm_isb(0xf);
159+
#elif defined(LIBC_TARGET_ARCH_IS_AARCH64)
160+
asm volatile("isb\n" ::: "memory");
161+
#else
162+
// Simply do nothing if sleeping isn't supported on this platform.
163+
#endif
164+
}
165+
24166
/// Conditional to indicate if this process is running on the GPU.
25167
LIBC_INLINE constexpr bool is_process_gpu() {
26168
#ifdef RPC_TARGET_IS_GPU
@@ -109,7 +251,7 @@ template <typename V> LIBC_INLINE V &lane_value(V *val, uint32_t id) {
109251

110252
/// Advance the \p p by \p bytes.
111253
template <typename T, typename U> LIBC_INLINE T *advance(T *ptr, U bytes) {
112-
if constexpr (cpp::is_const_v<T>)
254+
if constexpr (is_const<T>::value)
113255
return reinterpret_cast<T *>(reinterpret_cast<const uint8_t *>(ptr) +
114256
bytes);
115257
else

0 commit comments

Comments
 (0)