xref: /llvm-project/libc/src/stdio/gpu/vfprintf_utils.h (revision a6ef0debb1d60966b5bcc69f7d58a2b75c9c621d)
140effc7aSJoseph Huber //===--- GPU helper functions for printf using RPC ------------------------===//
240effc7aSJoseph Huber //
340effc7aSJoseph Huber // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
440effc7aSJoseph Huber // See https://llvm.org/LICENSE.txt for license information.
540effc7aSJoseph Huber // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
640effc7aSJoseph Huber //
740effc7aSJoseph Huber //===----------------------------------------------------------------------===//
840effc7aSJoseph Huber 
9c63112a9Slntue #include "hdr/types/FILE.h"
10197e0125SJoseph Huber #include "src/__support/GPU/utils.h"
1140effc7aSJoseph Huber #include "src/__support/RPC/rpc_client.h"
1240effc7aSJoseph Huber #include "src/__support/arg_list.h"
1303dcefe0SJoseph Huber #include "src/__support/macros/config.h"
1440effc7aSJoseph Huber #include "src/stdio/gpu/file.h"
1540effc7aSJoseph Huber #include "src/string/string_utils.h"
1640effc7aSJoseph Huber 
1703dcefe0SJoseph Huber namespace LIBC_NAMESPACE_DECL {
1840effc7aSJoseph Huber 
1927d25d1cSJoseph Huber template <uint32_t opcode>
2040effc7aSJoseph Huber LIBC_INLINE int vfprintf_impl(::FILE *__restrict file,
2140effc7aSJoseph Huber                               const char *__restrict format, size_t format_size,
2240effc7aSJoseph Huber                               va_list vlist) {
2340effc7aSJoseph Huber   uint64_t mask = gpu::get_lane_mask();
2440effc7aSJoseph Huber   rpc::Client::Port port = rpc::client.open<opcode>();
2540effc7aSJoseph Huber 
26*a6ef0debSJoseph Huber   if constexpr (opcode == LIBC_PRINTF_TO_STREAM ||
27*a6ef0debSJoseph Huber                 opcode == LIBC_PRINTF_TO_STREAM_PACKED) {
28be0c67c9SJoseph Huber     port.send([&](rpc::Buffer *buffer, uint32_t) {
2940effc7aSJoseph Huber       buffer->data[0] = reinterpret_cast<uintptr_t>(file);
3040effc7aSJoseph Huber     });
3140effc7aSJoseph Huber   }
3240effc7aSJoseph Huber 
3340effc7aSJoseph Huber   size_t args_size = 0;
3440effc7aSJoseph Huber   port.send_n(format, format_size);
35be0c67c9SJoseph Huber   port.recv([&](rpc::Buffer *buffer, uint32_t) {
3640effc7aSJoseph Huber     args_size = static_cast<size_t>(buffer->data[0]);
3740effc7aSJoseph Huber   });
3840effc7aSJoseph Huber   port.send_n(vlist, args_size);
3940effc7aSJoseph Huber 
4040effc7aSJoseph Huber   uint32_t ret = 0;
4140effc7aSJoseph Huber   for (;;) {
4240effc7aSJoseph Huber     const char *str = nullptr;
43be0c67c9SJoseph Huber     port.recv([&](rpc::Buffer *buffer, uint32_t) {
4440effc7aSJoseph Huber       ret = static_cast<uint32_t>(buffer->data[0]);
4540effc7aSJoseph Huber       str = reinterpret_cast<const char *>(buffer->data[1]);
4640effc7aSJoseph Huber     });
4740effc7aSJoseph Huber     // If any lanes have a string argument it needs to be copied back.
4840effc7aSJoseph Huber     if (!gpu::ballot(mask, str))
4940effc7aSJoseph Huber       break;
5040effc7aSJoseph Huber 
5140effc7aSJoseph Huber     uint64_t size = str ? internal::string_length(str) + 1 : 0;
5240effc7aSJoseph Huber     port.send_n(str, size);
5340effc7aSJoseph Huber   }
5440effc7aSJoseph Huber 
5540effc7aSJoseph Huber   port.close();
5640effc7aSJoseph Huber   return ret;
5740effc7aSJoseph Huber }
5840effc7aSJoseph Huber 
5940effc7aSJoseph Huber LIBC_INLINE int vfprintf_internal(::FILE *__restrict stream,
6040effc7aSJoseph Huber                                   const char *__restrict format,
6140effc7aSJoseph Huber                                   size_t format_size, va_list vlist) {
6240effc7aSJoseph Huber   // The AMDPGU backend uses a packed struct for its varargs. We pass it as a
6340effc7aSJoseph Huber   // separate opcode so the server knows how much to advance the pointers.
6440effc7aSJoseph Huber #if defined(LIBC_TARGET_ARCH_IS_AMDGPU)
6540effc7aSJoseph Huber   if (stream == stdout)
66*a6ef0debSJoseph Huber     return vfprintf_impl<LIBC_PRINTF_TO_STDOUT_PACKED>(stream, format,
6740effc7aSJoseph Huber                                                        format_size, vlist);
6840effc7aSJoseph Huber   else if (stream == stderr)
69*a6ef0debSJoseph Huber     return vfprintf_impl<LIBC_PRINTF_TO_STDERR_PACKED>(stream, format,
7040effc7aSJoseph Huber                                                        format_size, vlist);
7140effc7aSJoseph Huber   else
72*a6ef0debSJoseph Huber     return vfprintf_impl<LIBC_PRINTF_TO_STREAM_PACKED>(stream, format,
7340effc7aSJoseph Huber                                                        format_size, vlist);
7440effc7aSJoseph Huber #else
7540effc7aSJoseph Huber   if (stream == stdout)
76*a6ef0debSJoseph Huber     return vfprintf_impl<LIBC_PRINTF_TO_STDOUT>(stream, format, format_size,
7740effc7aSJoseph Huber                                                 vlist);
7840effc7aSJoseph Huber   else if (stream == stderr)
79*a6ef0debSJoseph Huber     return vfprintf_impl<LIBC_PRINTF_TO_STDERR>(stream, format, format_size,
8040effc7aSJoseph Huber                                                 vlist);
8140effc7aSJoseph Huber   else
82*a6ef0debSJoseph Huber     return vfprintf_impl<LIBC_PRINTF_TO_STREAM>(stream, format, format_size,
8340effc7aSJoseph Huber                                                 vlist);
8440effc7aSJoseph Huber #endif
8540effc7aSJoseph Huber }
8640effc7aSJoseph Huber 
8703dcefe0SJoseph Huber } // namespace LIBC_NAMESPACE_DECL
88