1*71db0c75SAndroid Build Coastguard Worker //===-- Shared memory RPC client / server utilities -------------*- C++ -*-===// 2*71db0c75SAndroid Build Coastguard Worker // 3*71db0c75SAndroid Build Coastguard Worker // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*71db0c75SAndroid Build Coastguard Worker // See https://llvm.org/LICENSE.txt for license information. 5*71db0c75SAndroid Build Coastguard Worker // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*71db0c75SAndroid Build Coastguard Worker // 7*71db0c75SAndroid Build Coastguard Worker //===----------------------------------------------------------------------===// 8*71db0c75SAndroid Build Coastguard Worker 9*71db0c75SAndroid Build Coastguard Worker #ifndef LLVM_LIBC_SHARED_RPC_UTIL_H 10*71db0c75SAndroid Build Coastguard Worker #define LLVM_LIBC_SHARED_RPC_UTIL_H 11*71db0c75SAndroid Build Coastguard Worker 12*71db0c75SAndroid Build Coastguard Worker #include <stddef.h> 13*71db0c75SAndroid Build Coastguard Worker #include <stdint.h> 14*71db0c75SAndroid Build Coastguard Worker 15*71db0c75SAndroid Build Coastguard Worker #if defined(__NVPTX__) || defined(__AMDGPU__) 16*71db0c75SAndroid Build Coastguard Worker #include <gpuintrin.h> 17*71db0c75SAndroid Build Coastguard Worker #define RPC_TARGET_IS_GPU 18*71db0c75SAndroid Build Coastguard Worker #endif 19*71db0c75SAndroid Build Coastguard Worker 20*71db0c75SAndroid Build Coastguard Worker // Workaround for missing __has_builtin in < GCC 10. 21*71db0c75SAndroid Build Coastguard Worker #ifndef __has_builtin 22*71db0c75SAndroid Build Coastguard Worker #define __has_builtin(x) 0 23*71db0c75SAndroid Build Coastguard Worker #endif 24*71db0c75SAndroid Build Coastguard Worker 25*71db0c75SAndroid Build Coastguard Worker #ifndef RPC_INLINE 26*71db0c75SAndroid Build Coastguard Worker #define RPC_INLINE inline 27*71db0c75SAndroid Build Coastguard Worker #endif 28*71db0c75SAndroid Build Coastguard Worker 29*71db0c75SAndroid Build Coastguard Worker namespace rpc { 30*71db0c75SAndroid Build Coastguard Worker 31*71db0c75SAndroid Build Coastguard Worker template <typename T> struct type_identity { 32*71db0c75SAndroid Build Coastguard Worker using type = T; 33*71db0c75SAndroid Build Coastguard Worker }; 34*71db0c75SAndroid Build Coastguard Worker 35*71db0c75SAndroid Build Coastguard Worker template <class T, T v> struct type_constant { 36*71db0c75SAndroid Build Coastguard Worker static inline constexpr T value = v; 37*71db0c75SAndroid Build Coastguard Worker }; 38*71db0c75SAndroid Build Coastguard Worker 39*71db0c75SAndroid Build Coastguard Worker template <class T> struct remove_reference : type_identity<T> {}; 40*71db0c75SAndroid Build Coastguard Worker template <class T> struct remove_reference<T &> : type_identity<T> {}; 41*71db0c75SAndroid Build Coastguard Worker template <class T> struct remove_reference<T &&> : type_identity<T> {}; 42*71db0c75SAndroid Build Coastguard Worker 43*71db0c75SAndroid Build Coastguard Worker template <class T> struct is_const : type_constant<bool, false> {}; 44*71db0c75SAndroid Build Coastguard Worker template <class T> struct is_const<const T> : type_constant<bool, true> {}; 45*71db0c75SAndroid Build Coastguard Worker 46*71db0c75SAndroid Build Coastguard Worker /// Freestanding implementation of std::move. 47*71db0c75SAndroid Build Coastguard Worker template <class T> 48*71db0c75SAndroid Build Coastguard Worker RPC_INLINE constexpr typename remove_reference<T>::type &&move(T &&t) { 49*71db0c75SAndroid Build Coastguard Worker return static_cast<typename remove_reference<T>::type &&>(t); 50*71db0c75SAndroid Build Coastguard Worker } 51*71db0c75SAndroid Build Coastguard Worker 52*71db0c75SAndroid Build Coastguard Worker /// Freestanding implementation of std::forward. 53*71db0c75SAndroid Build Coastguard Worker template <typename T> 54*71db0c75SAndroid Build Coastguard Worker RPC_INLINE constexpr T &&forward(typename remove_reference<T>::type &value) { 55*71db0c75SAndroid Build Coastguard Worker return static_cast<T &&>(value); 56*71db0c75SAndroid Build Coastguard Worker } 57*71db0c75SAndroid Build Coastguard Worker template <typename T> 58*71db0c75SAndroid Build Coastguard Worker RPC_INLINE constexpr T &&forward(typename remove_reference<T>::type &&value) { 59*71db0c75SAndroid Build Coastguard Worker return static_cast<T &&>(value); 60*71db0c75SAndroid Build Coastguard Worker } 61*71db0c75SAndroid Build Coastguard Worker 62*71db0c75SAndroid Build Coastguard Worker struct in_place_t { 63*71db0c75SAndroid Build Coastguard Worker RPC_INLINE explicit in_place_t() = default; 64*71db0c75SAndroid Build Coastguard Worker }; 65*71db0c75SAndroid Build Coastguard Worker 66*71db0c75SAndroid Build Coastguard Worker struct nullopt_t { 67*71db0c75SAndroid Build Coastguard Worker RPC_INLINE constexpr explicit nullopt_t() = default; 68*71db0c75SAndroid Build Coastguard Worker }; 69*71db0c75SAndroid Build Coastguard Worker 70*71db0c75SAndroid Build Coastguard Worker constexpr inline in_place_t in_place{}; 71*71db0c75SAndroid Build Coastguard Worker constexpr inline nullopt_t nullopt{}; 72*71db0c75SAndroid Build Coastguard Worker 73*71db0c75SAndroid Build Coastguard Worker /// Freestanding and minimal implementation of std::optional. 74*71db0c75SAndroid Build Coastguard Worker template <typename T> class optional { 75*71db0c75SAndroid Build Coastguard Worker template <typename U> struct OptionalStorage { 76*71db0c75SAndroid Build Coastguard Worker union { 77*71db0c75SAndroid Build Coastguard Worker char empty; 78*71db0c75SAndroid Build Coastguard Worker U stored_value; 79*71db0c75SAndroid Build Coastguard Worker }; 80*71db0c75SAndroid Build Coastguard Worker 81*71db0c75SAndroid Build Coastguard Worker bool in_use = false; 82*71db0c75SAndroid Build Coastguard Worker 83*71db0c75SAndroid Build Coastguard Worker RPC_INLINE ~OptionalStorage() { reset(); } 84*71db0c75SAndroid Build Coastguard Worker 85*71db0c75SAndroid Build Coastguard Worker RPC_INLINE constexpr OptionalStorage() : empty() {} 86*71db0c75SAndroid Build Coastguard Worker 87*71db0c75SAndroid Build Coastguard Worker template <typename... Args> 88*71db0c75SAndroid Build Coastguard Worker RPC_INLINE constexpr explicit OptionalStorage(in_place_t, Args &&...args) 89*71db0c75SAndroid Build Coastguard Worker : stored_value(forward<Args>(args)...) {} 90*71db0c75SAndroid Build Coastguard Worker 91*71db0c75SAndroid Build Coastguard Worker RPC_INLINE constexpr void reset() { 92*71db0c75SAndroid Build Coastguard Worker if (in_use) 93*71db0c75SAndroid Build Coastguard Worker stored_value.~U(); 94*71db0c75SAndroid Build Coastguard Worker in_use = false; 95*71db0c75SAndroid Build Coastguard Worker } 96*71db0c75SAndroid Build Coastguard Worker }; 97*71db0c75SAndroid Build Coastguard Worker 98*71db0c75SAndroid Build Coastguard Worker OptionalStorage<T> storage; 99*71db0c75SAndroid Build Coastguard Worker 100*71db0c75SAndroid Build Coastguard Worker public: 101*71db0c75SAndroid Build Coastguard Worker RPC_INLINE constexpr optional() = default; 102*71db0c75SAndroid Build Coastguard Worker RPC_INLINE constexpr optional(nullopt_t) {} 103*71db0c75SAndroid Build Coastguard Worker 104*71db0c75SAndroid Build Coastguard Worker RPC_INLINE constexpr optional(const T &t) : storage(in_place, t) { 105*71db0c75SAndroid Build Coastguard Worker storage.in_use = true; 106*71db0c75SAndroid Build Coastguard Worker } 107*71db0c75SAndroid Build Coastguard Worker RPC_INLINE constexpr optional(const optional &) = default; 108*71db0c75SAndroid Build Coastguard Worker 109*71db0c75SAndroid Build Coastguard Worker RPC_INLINE constexpr optional(T &&t) : storage(in_place, move(t)) { 110*71db0c75SAndroid Build Coastguard Worker storage.in_use = true; 111*71db0c75SAndroid Build Coastguard Worker } 112*71db0c75SAndroid Build Coastguard Worker RPC_INLINE constexpr optional(optional &&O) = default; 113*71db0c75SAndroid Build Coastguard Worker 114*71db0c75SAndroid Build Coastguard Worker RPC_INLINE constexpr optional &operator=(T &&t) { 115*71db0c75SAndroid Build Coastguard Worker storage = move(t); 116*71db0c75SAndroid Build Coastguard Worker return *this; 117*71db0c75SAndroid Build Coastguard Worker } 118*71db0c75SAndroid Build Coastguard Worker RPC_INLINE constexpr optional &operator=(optional &&) = default; 119*71db0c75SAndroid Build Coastguard Worker 120*71db0c75SAndroid Build Coastguard Worker RPC_INLINE constexpr optional &operator=(const T &t) { 121*71db0c75SAndroid Build Coastguard Worker storage = t; 122*71db0c75SAndroid Build Coastguard Worker return *this; 123*71db0c75SAndroid Build Coastguard Worker } 124*71db0c75SAndroid Build Coastguard Worker RPC_INLINE constexpr optional &operator=(const optional &) = default; 125*71db0c75SAndroid Build Coastguard Worker 126*71db0c75SAndroid Build Coastguard Worker RPC_INLINE constexpr void reset() { storage.reset(); } 127*71db0c75SAndroid Build Coastguard Worker 128*71db0c75SAndroid Build Coastguard Worker RPC_INLINE constexpr const T &value() const & { return storage.stored_value; } 129*71db0c75SAndroid Build Coastguard Worker 130*71db0c75SAndroid Build Coastguard Worker RPC_INLINE constexpr T &value() & { return storage.stored_value; } 131*71db0c75SAndroid Build Coastguard Worker 132*71db0c75SAndroid Build Coastguard Worker RPC_INLINE constexpr explicit operator bool() const { return storage.in_use; } 133*71db0c75SAndroid Build Coastguard Worker RPC_INLINE constexpr bool has_value() const { return storage.in_use; } 134*71db0c75SAndroid Build Coastguard Worker RPC_INLINE constexpr const T *operator->() const { 135*71db0c75SAndroid Build Coastguard Worker return &storage.stored_value; 136*71db0c75SAndroid Build Coastguard Worker } 137*71db0c75SAndroid Build Coastguard Worker RPC_INLINE constexpr T *operator->() { return &storage.stored_value; } 138*71db0c75SAndroid Build Coastguard Worker RPC_INLINE constexpr const T &operator*() const & { 139*71db0c75SAndroid Build Coastguard Worker return storage.stored_value; 140*71db0c75SAndroid Build Coastguard Worker } 141*71db0c75SAndroid Build Coastguard Worker RPC_INLINE constexpr T &operator*() & { return storage.stored_value; } 142*71db0c75SAndroid Build Coastguard Worker 143*71db0c75SAndroid Build Coastguard Worker RPC_INLINE constexpr T &&value() && { return move(storage.stored_value); } 144*71db0c75SAndroid Build Coastguard Worker RPC_INLINE constexpr T &&operator*() && { return move(storage.stored_value); } 145*71db0c75SAndroid Build Coastguard Worker }; 146*71db0c75SAndroid Build Coastguard Worker 147*71db0c75SAndroid Build Coastguard Worker /// Suspend the thread briefly to assist the thread scheduler during busy loops. 148*71db0c75SAndroid Build Coastguard Worker RPC_INLINE void sleep_briefly() { 149*71db0c75SAndroid Build Coastguard Worker #if defined(__NVPTX__) 150*71db0c75SAndroid Build Coastguard Worker if (__nvvm_reflect("__CUDA_ARCH") >= 700) 151*71db0c75SAndroid Build Coastguard Worker asm("nanosleep.u32 64;" ::: "memory"); 152*71db0c75SAndroid Build Coastguard Worker #elif defined(__AMDGPU__) 153*71db0c75SAndroid Build Coastguard Worker __builtin_amdgcn_s_sleep(2); 154*71db0c75SAndroid Build Coastguard Worker #elif __has_builtin(__builtin_ia32_pause) 155*71db0c75SAndroid Build Coastguard Worker __builtin_ia32_pause(); 156*71db0c75SAndroid Build Coastguard Worker #elif __has_builtin(__builtin_arm_isb) 157*71db0c75SAndroid Build Coastguard Worker __builtin_arm_isb(0xf); 158*71db0c75SAndroid Build Coastguard Worker #else 159*71db0c75SAndroid Build Coastguard Worker // Simply do nothing if sleeping isn't supported on this platform. 160*71db0c75SAndroid Build Coastguard Worker #endif 161*71db0c75SAndroid Build Coastguard Worker } 162*71db0c75SAndroid Build Coastguard Worker 163*71db0c75SAndroid Build Coastguard Worker /// Conditional to indicate if this process is running on the GPU. 164*71db0c75SAndroid Build Coastguard Worker RPC_INLINE constexpr bool is_process_gpu() { 165*71db0c75SAndroid Build Coastguard Worker #ifdef RPC_TARGET_IS_GPU 166*71db0c75SAndroid Build Coastguard Worker return true; 167*71db0c75SAndroid Build Coastguard Worker #else 168*71db0c75SAndroid Build Coastguard Worker return false; 169*71db0c75SAndroid Build Coastguard Worker #endif 170*71db0c75SAndroid Build Coastguard Worker } 171*71db0c75SAndroid Build Coastguard Worker 172*71db0c75SAndroid Build Coastguard Worker /// Wait for all lanes in the group to complete. 173*71db0c75SAndroid Build Coastguard Worker RPC_INLINE void sync_lane(uint64_t lane_mask) { 174*71db0c75SAndroid Build Coastguard Worker #ifdef RPC_TARGET_IS_GPU 175*71db0c75SAndroid Build Coastguard Worker return __gpu_sync_lane(lane_mask); 176*71db0c75SAndroid Build Coastguard Worker #endif 177*71db0c75SAndroid Build Coastguard Worker } 178*71db0c75SAndroid Build Coastguard Worker 179*71db0c75SAndroid Build Coastguard Worker /// Copies the value from the first active thread to the rest. 180*71db0c75SAndroid Build Coastguard Worker RPC_INLINE uint32_t broadcast_value(uint64_t lane_mask, uint32_t x) { 181*71db0c75SAndroid Build Coastguard Worker #ifdef RPC_TARGET_IS_GPU 182*71db0c75SAndroid Build Coastguard Worker return __gpu_read_first_lane_u32(lane_mask, x); 183*71db0c75SAndroid Build Coastguard Worker #else 184*71db0c75SAndroid Build Coastguard Worker return x; 185*71db0c75SAndroid Build Coastguard Worker #endif 186*71db0c75SAndroid Build Coastguard Worker } 187*71db0c75SAndroid Build Coastguard Worker 188*71db0c75SAndroid Build Coastguard Worker /// Returns the number lanes that participate in the RPC interface. 189*71db0c75SAndroid Build Coastguard Worker RPC_INLINE uint32_t get_num_lanes() { 190*71db0c75SAndroid Build Coastguard Worker #ifdef RPC_TARGET_IS_GPU 191*71db0c75SAndroid Build Coastguard Worker return __gpu_num_lanes(); 192*71db0c75SAndroid Build Coastguard Worker #else 193*71db0c75SAndroid Build Coastguard Worker return 1; 194*71db0c75SAndroid Build Coastguard Worker #endif 195*71db0c75SAndroid Build Coastguard Worker } 196*71db0c75SAndroid Build Coastguard Worker 197*71db0c75SAndroid Build Coastguard Worker /// Returns the id of the thread inside of an AMD wavefront executing together. 198*71db0c75SAndroid Build Coastguard Worker RPC_INLINE uint64_t get_lane_mask() { 199*71db0c75SAndroid Build Coastguard Worker #ifdef RPC_TARGET_IS_GPU 200*71db0c75SAndroid Build Coastguard Worker return __gpu_lane_mask(); 201*71db0c75SAndroid Build Coastguard Worker #else 202*71db0c75SAndroid Build Coastguard Worker return 1; 203*71db0c75SAndroid Build Coastguard Worker #endif 204*71db0c75SAndroid Build Coastguard Worker } 205*71db0c75SAndroid Build Coastguard Worker 206*71db0c75SAndroid Build Coastguard Worker /// Returns the id of the thread inside of an AMD wavefront executing together. 207*71db0c75SAndroid Build Coastguard Worker RPC_INLINE uint32_t get_lane_id() { 208*71db0c75SAndroid Build Coastguard Worker #ifdef RPC_TARGET_IS_GPU 209*71db0c75SAndroid Build Coastguard Worker return __gpu_lane_id(); 210*71db0c75SAndroid Build Coastguard Worker #else 211*71db0c75SAndroid Build Coastguard Worker return 0; 212*71db0c75SAndroid Build Coastguard Worker #endif 213*71db0c75SAndroid Build Coastguard Worker } 214*71db0c75SAndroid Build Coastguard Worker 215*71db0c75SAndroid Build Coastguard Worker /// Conditional that is only true for a single thread in a lane. 216*71db0c75SAndroid Build Coastguard Worker RPC_INLINE bool is_first_lane(uint64_t lane_mask) { 217*71db0c75SAndroid Build Coastguard Worker #ifdef RPC_TARGET_IS_GPU 218*71db0c75SAndroid Build Coastguard Worker return __gpu_is_first_in_lane(lane_mask); 219*71db0c75SAndroid Build Coastguard Worker #else 220*71db0c75SAndroid Build Coastguard Worker return true; 221*71db0c75SAndroid Build Coastguard Worker #endif 222*71db0c75SAndroid Build Coastguard Worker } 223*71db0c75SAndroid Build Coastguard Worker 224*71db0c75SAndroid Build Coastguard Worker /// Returns a bitmask of threads in the current lane for which \p x is true. 225*71db0c75SAndroid Build Coastguard Worker RPC_INLINE uint64_t ballot(uint64_t lane_mask, bool x) { 226*71db0c75SAndroid Build Coastguard Worker #ifdef RPC_TARGET_IS_GPU 227*71db0c75SAndroid Build Coastguard Worker return __gpu_ballot(lane_mask, x); 228*71db0c75SAndroid Build Coastguard Worker #else 229*71db0c75SAndroid Build Coastguard Worker return x; 230*71db0c75SAndroid Build Coastguard Worker #endif 231*71db0c75SAndroid Build Coastguard Worker } 232*71db0c75SAndroid Build Coastguard Worker 233*71db0c75SAndroid Build Coastguard Worker /// Return \p val aligned "upwards" according to \p align. 234*71db0c75SAndroid Build Coastguard Worker template <typename V, typename A> 235*71db0c75SAndroid Build Coastguard Worker RPC_INLINE constexpr V align_up(V val, A align) { 236*71db0c75SAndroid Build Coastguard Worker return ((val + V(align) - 1) / V(align)) * V(align); 237*71db0c75SAndroid Build Coastguard Worker } 238*71db0c75SAndroid Build Coastguard Worker 239*71db0c75SAndroid Build Coastguard Worker /// Utility to provide a unified interface between the CPU and GPU's memory 240*71db0c75SAndroid Build Coastguard Worker /// model. On the GPU stack variables are always private to a lane so we can 241*71db0c75SAndroid Build Coastguard Worker /// simply use the variable passed in. On the CPU we need to allocate enough 242*71db0c75SAndroid Build Coastguard Worker /// space for the whole lane and index into it. 243*71db0c75SAndroid Build Coastguard Worker template <typename V> RPC_INLINE V &lane_value(V *val, uint32_t id) { 244*71db0c75SAndroid Build Coastguard Worker if constexpr (is_process_gpu()) 245*71db0c75SAndroid Build Coastguard Worker return *val; 246*71db0c75SAndroid Build Coastguard Worker return val[id]; 247*71db0c75SAndroid Build Coastguard Worker } 248*71db0c75SAndroid Build Coastguard Worker 249*71db0c75SAndroid Build Coastguard Worker /// Advance the \p p by \p bytes. 250*71db0c75SAndroid Build Coastguard Worker template <typename T, typename U> RPC_INLINE T *advance(T *ptr, U bytes) { 251*71db0c75SAndroid Build Coastguard Worker if constexpr (is_const<T>::value) 252*71db0c75SAndroid Build Coastguard Worker return reinterpret_cast<T *>(reinterpret_cast<const uint8_t *>(ptr) + 253*71db0c75SAndroid Build Coastguard Worker bytes); 254*71db0c75SAndroid Build Coastguard Worker else 255*71db0c75SAndroid Build Coastguard Worker return reinterpret_cast<T *>(reinterpret_cast<uint8_t *>(ptr) + bytes); 256*71db0c75SAndroid Build Coastguard Worker } 257*71db0c75SAndroid Build Coastguard Worker 258*71db0c75SAndroid Build Coastguard Worker /// Wrapper around the optimal memory copy implementation for the target. 259*71db0c75SAndroid Build Coastguard Worker RPC_INLINE void rpc_memcpy(void *dst, const void *src, size_t count) { 260*71db0c75SAndroid Build Coastguard Worker __builtin_memcpy(dst, src, count); 261*71db0c75SAndroid Build Coastguard Worker } 262*71db0c75SAndroid Build Coastguard Worker 263*71db0c75SAndroid Build Coastguard Worker template <class T> RPC_INLINE constexpr const T &max(const T &a, const T &b) { 264*71db0c75SAndroid Build Coastguard Worker return (a < b) ? b : a; 265*71db0c75SAndroid Build Coastguard Worker } 266*71db0c75SAndroid Build Coastguard Worker 267*71db0c75SAndroid Build Coastguard Worker } // namespace rpc 268*71db0c75SAndroid Build Coastguard Worker 269*71db0c75SAndroid Build Coastguard Worker #endif // LLVM_LIBC_SHARED_RPC_UTIL_H 270