Skip to content

Commit

Permalink
[libc] Implement (v|f)printf on the GPU
Browse files Browse the repository at this point in the history
Summary:
This patch implements the `printf` family of functions on the GPU using
the new variadic support. This patch adapts the old handling in the
`rpc_fprintf` placeholder, but adds an extra RPC call to get the size of
the buffer to copy. This prevents the GPU from needing to parse the
string. While it's theoretically possible for the pass to know the size
of the struct, it's prohibitively difficult to do while maintaining ABI
compatibility with NVIDIA's varargs.

Depends on #96015.
  • Loading branch information
jhuber6 committed Jun 22, 2024
1 parent 3de162f commit 42a7a45
Show file tree
Hide file tree
Showing 18 changed files with 326 additions and 68 deletions.
1 change: 1 addition & 0 deletions clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1671,6 +1671,7 @@ int main(int Argc, char **Argv) {
NewArgv.push_back(Arg->getValue());
for (const opt::Arg *Arg : Args.filtered(OPT_offload_opt_eq_minus))
NewArgv.push_back(Args.MakeArgString(StringRef("-") + Arg->getValue()));
llvm::errs() << "asdfasdf\n";
cl::ParseCommandLineOptions(NewArgv.size(), &NewArgv[0]);

Verbose = Args.hasArg(OPT_verbose);
Expand Down
19 changes: 8 additions & 11 deletions libc/config/gpu/entrypoints.txt
Original file line number Diff line number Diff line change
@@ -1,13 +1,3 @@
if(LIBC_TARGET_ARCHITECTURE_IS_AMDGPU)
set(extra_entrypoints
# stdio.h entrypoints
libc.src.stdio.sprintf
libc.src.stdio.snprintf
libc.src.stdio.vsprintf
libc.src.stdio.vsnprintf
)
endif()

set(TARGET_LIBC_ENTRYPOINTS
# assert.h entrypoints
libc.src.assert.__assert_fail
Expand Down Expand Up @@ -185,7 +175,14 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.errno.errno

# stdio.h entrypoints
${extra_entrypoints}
libc.src.stdio.printf
libc.src.stdio.vprintf
libc.src.stdio.fprintf
libc.src.stdio.vfprintf
libc.src.stdio.sprintf
libc.src.stdio.snprintf
libc.src.stdio.vsprintf
libc.src.stdio.vsnprintf
libc.src.stdio.feof
libc.src.stdio.ferror
libc.src.stdio.fseek
Expand Down
3 changes: 2 additions & 1 deletion libc/src/__support/arg_list.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,8 @@ class MockArgList {
}

template <class T> LIBC_INLINE T next_var() {
++arg_counter;
arg_counter =
((arg_counter + alignof(T) - 1) / alignof(T)) * alignof(T) + sizeof(T);
return T(arg_counter);
}

Expand Down
5 changes: 4 additions & 1 deletion libc/src/gpu/rpc_fprintf.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ int fprintf_impl(::FILE *__restrict file, const char *__restrict format,
}

port.send_n(format, format_size);
port.recv([&](rpc::Buffer *buffer) {
args_size = static_cast<size_t>(buffer->data[0]);
});
port.send_n(args, args_size);

uint32_t ret = 0;
Expand All @@ -50,7 +53,7 @@ int fprintf_impl(::FILE *__restrict file, const char *__restrict format,
return ret;
}

// TODO: This is a stand-in function that uses a struct pointer and size in
// TODO: Delete this and port OpenMP to use `printf`.
// place of varargs. Once varargs support is added we will use that to
// implement the real version.
LLVM_LIBC_FUNCTION(int, rpc_fprintf,
Expand Down
24 changes: 2 additions & 22 deletions libc/src/stdio/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -159,17 +159,6 @@ add_entrypoint_object(
libc.src.stdio.printf_core.writer
)

add_entrypoint_object(
fprintf
SRCS
fprintf.cpp
HDRS
fprintf.h
DEPENDS
libc.src.__support.arg_list
libc.src.stdio.printf_core.vfprintf_internal
)

add_entrypoint_object(
vsprintf
SRCS
Expand All @@ -192,17 +181,6 @@ add_entrypoint_object(
libc.src.stdio.printf_core.writer
)

add_entrypoint_object(
vfprintf
SRCS
vfprintf.cpp
HDRS
vfprintf.h
DEPENDS
libc.src.__support.arg_list
libc.src.stdio.printf_core.vfprintf_internal
)

add_stdio_entrypoint_object(
fileno
SRCS
Expand Down Expand Up @@ -261,6 +239,7 @@ add_stdio_entrypoint_object(fputc)
add_stdio_entrypoint_object(putc)
add_stdio_entrypoint_object(putchar)
add_stdio_entrypoint_object(printf)
add_stdio_entrypoint_object(fprintf)
add_stdio_entrypoint_object(fgetc)
add_stdio_entrypoint_object(fgetc_unlocked)
add_stdio_entrypoint_object(getc)
Expand All @@ -273,3 +252,4 @@ add_stdio_entrypoint_object(stdin)
add_stdio_entrypoint_object(stdout)
add_stdio_entrypoint_object(stderr)
add_stdio_entrypoint_object(vprintf)
add_stdio_entrypoint_object(vfprintf)
25 changes: 25 additions & 0 deletions libc/src/stdio/generic/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,31 @@ add_entrypoint_object(
${printf_deps}
)

add_entrypoint_object(
fprintf
SRCS
fprintf.cpp
HDRS
../fprintf.h
DEPENDS
libc.src.__support.arg_list
libc.src.stdio.printf_core.vfprintf_internal
${printf_deps}
)

add_entrypoint_object(
vfprintf
SRCS
vfprintf.cpp
HDRS
../vfprintf.h
DEPENDS
libc.src.__support.arg_list
libc.src.stdio.printf_core.vfprintf_internal
${printf_deps}
)


add_entrypoint_object(
fgets
SRCS
Expand Down
File renamed without changes.
File renamed without changes.
48 changes: 48 additions & 0 deletions libc/src/stdio/gpu/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,14 @@ add_header_library(
.stderr
)

add_header_library(
vfprintf_utils
HDRS
vfprintf_utils.h
DEPENDS
.gpu_file
)

add_entrypoint_object(
feof
SRCS
Expand Down Expand Up @@ -262,6 +270,46 @@ add_entrypoint_object(
.gpu_file
)

add_entrypoint_object(
printf
SRCS
printf.cpp
HDRS
../printf.h
DEPENDS
.vfprintf_utils
)

add_entrypoint_object(
vprintf
SRCS
vprintf.cpp
HDRS
../vprintf.h
DEPENDS
.vfprintf_utils
)

add_entrypoint_object(
fprintf
SRCS
fprintf.cpp
HDRS
../fprintf.h
DEPENDS
.vfprintf_utils
)

add_entrypoint_object(
vfprintf
SRCS
vfprintf.cpp
HDRS
../vfprintf.h
DEPENDS
.vfprintf_utils
)

add_entrypoint_object(
stdin
SRCS
Expand Down
32 changes: 32 additions & 0 deletions libc/src/stdio/gpu/fprintf.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
//===-- GPU Implementation of fprintf -------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "src/stdio/fprintf.h"

#include "src/__support/CPP/string_view.h"
#include "src/__support/arg_list.h"
#include "src/errno/libc_errno.h"
#include "src/stdio/gpu/vfprintf_utils.h"

#include <stdio.h>

namespace LIBC_NAMESPACE {

LLVM_LIBC_FUNCTION(int, fprintf,
(::FILE *__restrict stream, const char *__restrict format,
...)) {
va_list vlist;
va_start(vlist, format);
cpp::string_view str_view(format);
int ret_val =
file::vfprintf_internal(stream, format, str_view.size() + 1, vlist);
va_end(vlist);
return ret_val;
}

} // namespace LIBC_NAMESPACE
30 changes: 30 additions & 0 deletions libc/src/stdio/gpu/printf.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
//===-- GPU Implementation of printf --------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "src/stdio/printf.h"

#include "src/__support/CPP/string_view.h"
#include "src/__support/arg_list.h"
#include "src/errno/libc_errno.h"
#include "src/stdio/gpu/vfprintf_utils.h"

#include <stdio.h>

namespace LIBC_NAMESPACE {

LLVM_LIBC_FUNCTION(int, printf, (const char *__restrict format, ...)) {
va_list vlist;
va_start(vlist, format);
cpp::string_view str_view(format);
int ret_val =
file::vfprintf_internal(stdout, format, str_view.size() + 1, vlist);
va_end(vlist);
return ret_val;
}

} // namespace LIBC_NAMESPACE
29 changes: 29 additions & 0 deletions libc/src/stdio/gpu/vfprintf.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
//===-- GPU Implementation of vfprintf ------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "src/stdio/vfprintf.h"

#include "src/__support/CPP/string_view.h"
#include "src/__support/arg_list.h"
#include "src/errno/libc_errno.h"
#include "src/stdio/gpu/vfprintf_utils.h"

#include <stdio.h>

namespace LIBC_NAMESPACE {

LLVM_LIBC_FUNCTION(int, vfprintf,
(::FILE *__restrict stream, const char *__restrict format,
va_list vlist)) {
cpp::string_view str_view(format);
int ret_val =
file::vfprintf_internal(stream, format, str_view.size() + 1, vlist);
return ret_val;
}

} // namespace LIBC_NAMESPACE
73 changes: 73 additions & 0 deletions libc/src/stdio/gpu/vfprintf_utils.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
//===--- GPU helper functions for printf using RPC ------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "src/__support/RPC/rpc_client.h"
#include "src/__support/arg_list.h"
#include "src/stdio/gpu/file.h"
#include "src/string/string_utils.h"

#include <stdio.h>

namespace LIBC_NAMESPACE {
namespace file {

template <uint16_t opcode>
LIBC_INLINE int vfprintf_impl(::FILE *__restrict file,
const char *__restrict format, size_t format_size,
va_list vlist) {
uint64_t mask = gpu::get_lane_mask();
rpc::Client::Port port = rpc::client.open<opcode>();

if constexpr (opcode == RPC_PRINTF_TO_STREAM) {
port.send([&](rpc::Buffer *buffer) {
buffer->data[0] = reinterpret_cast<uintptr_t>(file);
});
}

size_t args_size = 0;
port.send_n(format, format_size);
port.recv([&](rpc::Buffer *buffer) {
args_size = static_cast<size_t>(buffer->data[0]);
});
port.send_n(vlist, args_size);

uint32_t ret = 0;
for (;;) {
const char *str = nullptr;
port.recv([&](rpc::Buffer *buffer) {
ret = static_cast<uint32_t>(buffer->data[0]);
str = reinterpret_cast<const char *>(buffer->data[1]);
});
// If any lanes have a string argument it needs to be copied back.
if (!gpu::ballot(mask, str))
break;

uint64_t size = str ? internal::string_length(str) + 1 : 0;
port.send_n(str, size);
}

port.close();
return ret;
}

LIBC_INLINE int vfprintf_internal(::FILE *__restrict stream,
const char *__restrict format,
size_t format_size, va_list vlist) {
if (stream == stdout)
return vfprintf_impl<RPC_PRINTF_TO_STDOUT>(stream, format, format_size,
vlist);
else if (stream == stderr)
return vfprintf_impl<RPC_PRINTF_TO_STDERR>(stream, format, format_size,
vlist);
else
return vfprintf_impl<RPC_PRINTF_TO_STREAM>(stream, format, format_size,
vlist);
}

} // namespace file
} // namespace LIBC_NAMESPACE
Loading

0 comments on commit 42a7a45

Please sign in to comment.