1*71db0c75SAndroid Build Coastguard Worker //===--- GPU helper functions for printf using RPC ------------------------===//
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 #include "hdr/types/FILE.h"
10*71db0c75SAndroid Build Coastguard Worker #include "src/__support/GPU/utils.h"
11*71db0c75SAndroid Build Coastguard Worker #include "src/__support/RPC/rpc_client.h"
12*71db0c75SAndroid Build Coastguard Worker #include "src/__support/arg_list.h"
13*71db0c75SAndroid Build Coastguard Worker #include "src/__support/macros/config.h"
14*71db0c75SAndroid Build Coastguard Worker #include "src/stdio/gpu/file.h"
15*71db0c75SAndroid Build Coastguard Worker #include "src/string/string_utils.h"
16*71db0c75SAndroid Build Coastguard Worker
17*71db0c75SAndroid Build Coastguard Worker namespace LIBC_NAMESPACE_DECL {
18*71db0c75SAndroid Build Coastguard Worker
19*71db0c75SAndroid Build Coastguard Worker template <uint32_t opcode>
vfprintf_impl(::FILE * __restrict file,const char * __restrict format,size_t format_size,va_list vlist)20*71db0c75SAndroid Build Coastguard Worker LIBC_INLINE int vfprintf_impl(::FILE *__restrict file,
21*71db0c75SAndroid Build Coastguard Worker const char *__restrict format, size_t format_size,
22*71db0c75SAndroid Build Coastguard Worker va_list vlist) {
23*71db0c75SAndroid Build Coastguard Worker uint64_t mask = gpu::get_lane_mask();
24*71db0c75SAndroid Build Coastguard Worker rpc::Client::Port port = rpc::client.open<opcode>();
25*71db0c75SAndroid Build Coastguard Worker
26*71db0c75SAndroid Build Coastguard Worker if constexpr (opcode == RPC_PRINTF_TO_STREAM ||
27*71db0c75SAndroid Build Coastguard Worker opcode == RPC_PRINTF_TO_STREAM_PACKED) {
28*71db0c75SAndroid Build Coastguard Worker port.send([&](rpc::Buffer *buffer, uint32_t) {
29*71db0c75SAndroid Build Coastguard Worker buffer->data[0] = reinterpret_cast<uintptr_t>(file);
30*71db0c75SAndroid Build Coastguard Worker });
31*71db0c75SAndroid Build Coastguard Worker }
32*71db0c75SAndroid Build Coastguard Worker
33*71db0c75SAndroid Build Coastguard Worker size_t args_size = 0;
34*71db0c75SAndroid Build Coastguard Worker port.send_n(format, format_size);
35*71db0c75SAndroid Build Coastguard Worker port.recv([&](rpc::Buffer *buffer, uint32_t) {
36*71db0c75SAndroid Build Coastguard Worker args_size = static_cast<size_t>(buffer->data[0]);
37*71db0c75SAndroid Build Coastguard Worker });
38*71db0c75SAndroid Build Coastguard Worker port.send_n(vlist, args_size);
39*71db0c75SAndroid Build Coastguard Worker
40*71db0c75SAndroid Build Coastguard Worker uint32_t ret = 0;
41*71db0c75SAndroid Build Coastguard Worker for (;;) {
42*71db0c75SAndroid Build Coastguard Worker const char *str = nullptr;
43*71db0c75SAndroid Build Coastguard Worker port.recv([&](rpc::Buffer *buffer, uint32_t) {
44*71db0c75SAndroid Build Coastguard Worker ret = static_cast<uint32_t>(buffer->data[0]);
45*71db0c75SAndroid Build Coastguard Worker str = reinterpret_cast<const char *>(buffer->data[1]);
46*71db0c75SAndroid Build Coastguard Worker });
47*71db0c75SAndroid Build Coastguard Worker // If any lanes have a string argument it needs to be copied back.
48*71db0c75SAndroid Build Coastguard Worker if (!gpu::ballot(mask, str))
49*71db0c75SAndroid Build Coastguard Worker break;
50*71db0c75SAndroid Build Coastguard Worker
51*71db0c75SAndroid Build Coastguard Worker uint64_t size = str ? internal::string_length(str) + 1 : 0;
52*71db0c75SAndroid Build Coastguard Worker port.send_n(str, size);
53*71db0c75SAndroid Build Coastguard Worker }
54*71db0c75SAndroid Build Coastguard Worker
55*71db0c75SAndroid Build Coastguard Worker port.close();
56*71db0c75SAndroid Build Coastguard Worker return ret;
57*71db0c75SAndroid Build Coastguard Worker }
58*71db0c75SAndroid Build Coastguard Worker
vfprintf_internal(::FILE * __restrict stream,const char * __restrict format,size_t format_size,va_list vlist)59*71db0c75SAndroid Build Coastguard Worker LIBC_INLINE int vfprintf_internal(::FILE *__restrict stream,
60*71db0c75SAndroid Build Coastguard Worker const char *__restrict format,
61*71db0c75SAndroid Build Coastguard Worker size_t format_size, va_list vlist) {
62*71db0c75SAndroid Build Coastguard Worker // The AMDPGU backend uses a packed struct for its varargs. We pass it as a
63*71db0c75SAndroid Build Coastguard Worker // separate opcode so the server knows how much to advance the pointers.
64*71db0c75SAndroid Build Coastguard Worker #if defined(LIBC_TARGET_ARCH_IS_AMDGPU)
65*71db0c75SAndroid Build Coastguard Worker if (stream == stdout)
66*71db0c75SAndroid Build Coastguard Worker return vfprintf_impl<RPC_PRINTF_TO_STDOUT_PACKED>(stream, format,
67*71db0c75SAndroid Build Coastguard Worker format_size, vlist);
68*71db0c75SAndroid Build Coastguard Worker else if (stream == stderr)
69*71db0c75SAndroid Build Coastguard Worker return vfprintf_impl<RPC_PRINTF_TO_STDERR_PACKED>(stream, format,
70*71db0c75SAndroid Build Coastguard Worker format_size, vlist);
71*71db0c75SAndroid Build Coastguard Worker else
72*71db0c75SAndroid Build Coastguard Worker return vfprintf_impl<RPC_PRINTF_TO_STREAM_PACKED>(stream, format,
73*71db0c75SAndroid Build Coastguard Worker format_size, vlist);
74*71db0c75SAndroid Build Coastguard Worker #else
75*71db0c75SAndroid Build Coastguard Worker if (stream == stdout)
76*71db0c75SAndroid Build Coastguard Worker return vfprintf_impl<RPC_PRINTF_TO_STDOUT>(stream, format, format_size,
77*71db0c75SAndroid Build Coastguard Worker vlist);
78*71db0c75SAndroid Build Coastguard Worker else if (stream == stderr)
79*71db0c75SAndroid Build Coastguard Worker return vfprintf_impl<RPC_PRINTF_TO_STDERR>(stream, format, format_size,
80*71db0c75SAndroid Build Coastguard Worker vlist);
81*71db0c75SAndroid Build Coastguard Worker else
82*71db0c75SAndroid Build Coastguard Worker return vfprintf_impl<RPC_PRINTF_TO_STREAM>(stream, format, format_size,
83*71db0c75SAndroid Build Coastguard Worker vlist);
84*71db0c75SAndroid Build Coastguard Worker #endif
85*71db0c75SAndroid Build Coastguard Worker }
86*71db0c75SAndroid Build Coastguard Worker
87*71db0c75SAndroid Build Coastguard Worker } // namespace LIBC_NAMESPACE_DECL
88