Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[libc] Implement (v|f)printf on the GPU #96369

Merged
merged 1 commit into from
Jul 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions libc/config/gpu/entrypoints.txt
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,10 @@ set(TARGET_LIBC_ENTRYPOINTS
# stdio.h entrypoints
libc.src.stdio.clearerr
libc.src.stdio.fclose
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
Expand Down
3 changes: 3 additions & 0 deletions libc/include/llvm-libc-types/rpc_opcodes_t.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ typedef enum {
RPC_PRINTF_TO_STDOUT,
RPC_PRINTF_TO_STDERR,
RPC_PRINTF_TO_STREAM,
RPC_PRINTF_TO_STDOUT_PACKED,
RPC_PRINTF_TO_STDERR_PACKED,
RPC_PRINTF_TO_STREAM_PACKED,
RPC_REMOVE,
RPC_LAST = 0xFFFF,
} rpc_opcode_t;
Expand Down
51 changes: 43 additions & 8 deletions libc/src/__support/arg_list.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@
namespace LIBC_NAMESPACE_DECL {
namespace internal {

template <typename V, typename A>
LIBC_INLINE constexpr V align_up(V val, A align) {
return ((val + V(align) - 1) / V(align)) * V(align);
}

class ArgList {
va_list vlist;

Expand Down Expand Up @@ -55,7 +60,34 @@ class MockArgList {
}

template <class T> LIBC_INLINE T next_var() {
++arg_counter;
arg_counter++;
return T(arg_counter);
}

size_t read_count() const { return arg_counter; }
};

// Used by the GPU implementation to parse how many bytes need to be read from
// the variadic argument buffer.
template <bool packed> class DummyArgList {
size_t arg_counter = 0;

public:
LIBC_INLINE DummyArgList() = default;
LIBC_INLINE DummyArgList(va_list) { ; }
LIBC_INLINE DummyArgList(DummyArgList &other) {
arg_counter = other.arg_counter;
}
LIBC_INLINE ~DummyArgList() = default;

LIBC_INLINE DummyArgList &operator=(DummyArgList &rhs) {
arg_counter = rhs.arg_counter;
return *this;
}

template <class T> LIBC_INLINE T next_var() {
arg_counter = packed ? arg_counter + sizeof(T)
: align_up(arg_counter, alignof(T)) + sizeof(T);
return T(arg_counter);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe split this into separate increment by size and round for the alignment operations. There might be helper functions for the rounding which would be clearer than reading the division / multiplication and trying to pattern match on what alignment code usually looks like (e.g. I expected to see masking off bits so tripped over this)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's also __builtin_align_up and __builtin_align_down

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting, didn't know about that one. Doesn't seem like GCC supports it, and this is one of the files that gcc might compile so it's probably easier to keep it in a utility for now. Maybe I could do __has_builtin for clang.

}

Expand All @@ -64,7 +96,7 @@ class MockArgList {

// Used for the GPU implementation of `printf`. This models a variadic list as a
// simple array of pointers that are built manually by the implementation.
class StructArgList {
template <bool packed> class StructArgList {
void *ptr;
void *end;

Expand All @@ -86,15 +118,18 @@ class StructArgList {
LIBC_INLINE void *get_ptr() const { return ptr; }

template <class T> LIBC_INLINE T next_var() {
ptr = reinterpret_cast<void *>(
((reinterpret_cast<uintptr_t>(ptr) + alignof(T) - 1) / alignof(T)) *
alignof(T));

if (!packed)
ptr = reinterpret_cast<void *>(
align_up(reinterpret_cast<uintptr_t>(ptr), alignof(T)));
if (ptr >= end)
return T(-1);

T val = *reinterpret_cast<T *>(ptr);
ptr = reinterpret_cast<unsigned char *>(ptr) + sizeof(T);
// Memcpy because pointer alignment may be illegal given a packed struct.
T val;
__builtin_memcpy(&val, ptr, sizeof(T));

ptr =
reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(ptr) + sizeof(T));
return val;
}
};
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 @@ -30,6 +30,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 @@ -51,7 +54,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
26 changes: 2 additions & 24 deletions libc/src/stdio/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -163,18 +163,6 @@ add_entrypoint_object(
libc.src.stdio.printf_core.writer
)

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

add_entrypoint_object(
vsprintf
SRCS
Expand All @@ -197,18 +185,6 @@ add_entrypoint_object(
libc.src.stdio.printf_core.writer
)

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

add_subdirectory(printf_core)
add_subdirectory(scanf_core)

Expand Down Expand Up @@ -258,6 +234,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 @@ -270,3 +247,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)
39 changes: 26 additions & 13 deletions libc/src/stdio/generic/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -363,19 +363,6 @@ add_entrypoint_object(
libc.src.__support.File.platform_file
)

list(APPEND printf_deps
libc.src.__support.arg_list
libc.src.stdio.printf_core.vfprintf_internal
)

if(LLVM_LIBC_FULL_BUILD)
list(APPEND printf_deps
libc.src.__support.File.file
libc.src.__support.File.platform_file
libc.src.__support.File.platform_stdout
)
endif()

add_entrypoint_object(
printf
SRCS
Expand All @@ -396,6 +383,32 @@ add_entrypoint_object(
${printf_deps}
)

add_entrypoint_object(
fprintf
SRCS
fprintf.cpp
HDRS
../fprintf.h
DEPENDS
libc.hdr.types.FILE
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.hdr.types.FILE
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 @@ -11,6 +11,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 @@ -246,6 +254,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
31 changes: 31 additions & 0 deletions libc/src/stdio/gpu/fprintf.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
//===-- 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 = vfprintf_internal(stream, 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/printf.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
//===-- 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 = vfprintf_internal(stdout, format, str_view.size() + 1, vlist);
va_end(vlist);
return ret_val;
}

} // namespace LIBC_NAMESPACE
28 changes: 28 additions & 0 deletions libc/src/stdio/gpu/vfprintf.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
//===-- 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 = vfprintf_internal(stream, format, str_view.size() + 1, vlist);
return ret_val;
}

} // namespace LIBC_NAMESPACE
Loading
Loading