diff options
| author | Joseph Huber <35342157+jhuber6@users.noreply.github.com> | 2023-09-14 15:39:29 -0500 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-09-14 15:39:29 -0500 |
| commit | a1be5d69dff0ff9bdf0329370a3ce724bcd25ed2 (patch) | |
| tree | 4d6c93caba191693578233d95392351a7d9f9409 /libc/src/stdio/gpu | |
| parent | 96ccc81fb8bbe6a545d52c79cc66ae614241b0a4 (diff) | |
[libc] Implement more input functions on the GPU (#66288)
Summary:
This patch implements the `fgets`, `getc`, `fgetc`, and `getchar`
functions on the GPU. Their implementations are straightforward enough.
One thing worth noting is that the implementation of `fgets` will be
extremely slow due to the high latency to read a single char. A faster
solution would be to make a new RPC call to call `fgets` (due to the
special rule that newline or null breaks the stream). But this is left
out because performance isn't the primary concern here.
Diffstat (limited to 'libc/src/stdio/gpu')
| -rw-r--r-- | libc/src/stdio/gpu/CMakeLists.txt | 113 | ||||
| -rw-r--r-- | libc/src/stdio/gpu/clearerr.cpp | 24 | ||||
| -rw-r--r-- | libc/src/stdio/gpu/feof.cpp | 26 | ||||
| -rw-r--r-- | libc/src/stdio/gpu/ferror.cpp | 26 | ||||
| -rw-r--r-- | libc/src/stdio/gpu/fgetc.cpp | 25 | ||||
| -rw-r--r-- | libc/src/stdio/gpu/fgets.cpp | 46 | ||||
| -rw-r--r-- | libc/src/stdio/gpu/file.h | 33 | ||||
| -rw-r--r-- | libc/src/stdio/gpu/getc.cpp | 25 | ||||
| -rw-r--r-- | libc/src/stdio/gpu/getchar.cpp | 25 |
9 files changed, 343 insertions, 0 deletions
diff --git a/libc/src/stdio/gpu/CMakeLists.txt b/libc/src/stdio/gpu/CMakeLists.txt index d35b1925c6a4..c47176621144 100644 --- a/libc/src/stdio/gpu/CMakeLists.txt +++ b/libc/src/stdio/gpu/CMakeLists.txt @@ -3,6 +3,7 @@ add_header_library( HDRS file.h DEPENDS + libc.src.__support.RPC.rpc_client libc.src.__support.common .stdin .stdout @@ -10,6 +11,39 @@ add_header_library( ) add_entrypoint_object( + feof + SRCS + feof.cpp + HDRS + ../feof.h + DEPENDS + libc.include.stdio + libc.src.__support.RPC.rpc_client +) + +add_entrypoint_object( + ferror + SRCS + ferror.cpp + HDRS + ../ferror.h + DEPENDS + libc.include.stdio + libc.src.__support.RPC.rpc_client +) + +add_entrypoint_object( + clearerr + SRCS + clearerr.cpp + HDRS + ../clearerr.h + DEPENDS + libc.include.stdio + libc.src.__support.RPC.rpc_client +) + +add_entrypoint_object( fopen SRCS fopen.cpp @@ -106,6 +140,85 @@ add_entrypoint_object( ) add_entrypoint_object( + fgetc + SRCS + fgetc.cpp + HDRS + ../fgetc.h + DEPENDS + libc.include.stdio + .gpu_file +) + +add_entrypoint_object( + fgetc_unlocked + SRCS + fgetc_unlocked.cpp + HDRS + ../fgetc_unlocked.h + DEPENDS + libc.include.stdio + .gpu_file +) + +add_entrypoint_object( + getc + SRCS + getc.cpp + HDRS + ../getc.h + DEPENDS + libc.include.stdio + .gpu_file +) + +add_entrypoint_object( + getc_unlocked + SRCS + getc_unlocked.cpp + HDRS + ../getc_unlocked.h + DEPENDS + libc.include.stdio + .gpu_file +) + +add_entrypoint_object( + getchar + SRCS + getchar.cpp + HDRS + ../getchar.h + DEPENDS + libc.include.stdio + .gpu_file +) + +add_entrypoint_object( + getchar_unlocked + SRCS + getc_unlocked.cpp + HDRS + ../getc_unlocked.h + DEPENDS + libc.include.stdio + .gpu_file +) + +add_entrypoint_object( + fgets + SRCS + fgets.cpp + HDRS + ../fgets.h + DEPENDS + libc.include.stdio + .gpu_file + .feof + .ferror +) + +add_entrypoint_object( stdin SRCS stdin.cpp diff --git a/libc/src/stdio/gpu/clearerr.cpp b/libc/src/stdio/gpu/clearerr.cpp new file mode 100644 index 000000000000..dc7a3729aa78 --- /dev/null +++ b/libc/src/stdio/gpu/clearerr.cpp @@ -0,0 +1,24 @@ +//===-- Implementation of clearerr ----------------------------------------===// +// +// 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/clearerr.h" +#include "file.h" + +#include <stdio.h> + +namespace __llvm_libc { + +LLVM_LIBC_FUNCTION(void, clearerr, (::FILE * stream)) { + rpc::Client::Port port = rpc::client.open<RPC_FERROR>(); + port.send_and_recv( + [=](rpc::Buffer *buffer) { buffer->data[0] = file::from_stream(stream); }, + [&](rpc::Buffer *) {}); + port.close(); +} + +} // namespace __llvm_libc diff --git a/libc/src/stdio/gpu/feof.cpp b/libc/src/stdio/gpu/feof.cpp new file mode 100644 index 000000000000..27d27a445812 --- /dev/null +++ b/libc/src/stdio/gpu/feof.cpp @@ -0,0 +1,26 @@ +//===-- Implementation of feof --------------------------------------------===// +// +// 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/feof.h" +#include "file.h" + +#include <stdio.h> + +namespace __llvm_libc { + +LLVM_LIBC_FUNCTION(int, feof, (::FILE * stream)) { + int ret; + rpc::Client::Port port = rpc::client.open<RPC_FEOF>(); + port.send_and_recv( + [=](rpc::Buffer *buffer) { buffer->data[0] = file::from_stream(stream); }, + [&](rpc::Buffer *buffer) { ret = static_cast<int>(buffer->data[0]); }); + port.close(); + return ret; +} + +} // namespace __llvm_libc diff --git a/libc/src/stdio/gpu/ferror.cpp b/libc/src/stdio/gpu/ferror.cpp new file mode 100644 index 000000000000..e4bd631f392d --- /dev/null +++ b/libc/src/stdio/gpu/ferror.cpp @@ -0,0 +1,26 @@ +//===-- Implementation of ferror ------------------------------------------===// +// +// 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/ferror.h" +#include "file.h" + +#include <stdio.h> + +namespace __llvm_libc { + +LLVM_LIBC_FUNCTION(int, ferror, (::FILE * stream)) { + int ret; + rpc::Client::Port port = rpc::client.open<RPC_FERROR>(); + port.send_and_recv( + [=](rpc::Buffer *buffer) { buffer->data[0] = file::from_stream(stream); }, + [&](rpc::Buffer *buffer) { ret = static_cast<int>(buffer->data[0]); }); + port.close(); + return ret; +} + +} // namespace __llvm_libc diff --git a/libc/src/stdio/gpu/fgetc.cpp b/libc/src/stdio/gpu/fgetc.cpp new file mode 100644 index 000000000000..ff4ef27ccb88 --- /dev/null +++ b/libc/src/stdio/gpu/fgetc.cpp @@ -0,0 +1,25 @@ +//===-- GPU implementation of fgetc ---------------------------------------===// +// +// 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/fgetc.h" +#include "file.h" + +#include <stdio.h> + +namespace __llvm_libc { + +LLVM_LIBC_FUNCTION(int, fgetc, (::FILE * stream)) { + unsigned char c; + size_t r = file::read(stream, &c, 1); + + if (r != 1) + return EOF; + return c; +} + +} // namespace __llvm_libc diff --git a/libc/src/stdio/gpu/fgets.cpp b/libc/src/stdio/gpu/fgets.cpp new file mode 100644 index 000000000000..df00451e2a97 --- /dev/null +++ b/libc/src/stdio/gpu/fgets.cpp @@ -0,0 +1,46 @@ +//===-- GPU implementation of fgets ---------------------------------------===// +// +// 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/fgets.h" +#include "file.h" +#include "src/stdio/feof.h" +#include "src/stdio/ferror.h" + +#include <stddef.h> +#include <stdio.h> + +namespace __llvm_libc { + +LLVM_LIBC_FUNCTION(char *, fgets, + (char *__restrict str, int count, + ::FILE *__restrict stream)) { + if (count < 1) + return nullptr; + + // This implementation is very slow as it makes multiple RPC calls. + unsigned char c = '\0'; + int i = 0; + for (; i < count - 1 && c != '\n'; ++i) { + auto r = file::read(stream, &c, 1); + if (r != 1) + break; + + str[i] = c; + } + + bool has_error = __llvm_libc::ferror(stream); + bool has_eof = __llvm_libc::feof(stream); + + if (has_error || (i == 0 && has_eof)) + return nullptr; + + str[i] = '\0'; + return str; +} + +} // namespace __llvm_libc diff --git a/libc/src/stdio/gpu/file.h b/libc/src/stdio/gpu/file.h index 77817e070680..42395a6d4287 100644 --- a/libc/src/stdio/gpu/file.h +++ b/libc/src/stdio/gpu/file.h @@ -65,5 +65,38 @@ LIBC_INLINE uint64_t read(::FILE *f, void *data, size_t size) { return read_from_stream<RPC_READ_FROM_STREAM>(f, data, size); } +enum Stream { + File = 0, + Stdin = 1, + Stdout = 2, + Stderr = 3, +}; + +// When copying between the client and server we need to indicate if this is one +// of the special streams. We do this by enocding the low order bits of the +// pointer to indicate if we need to use the host's standard stream. +LIBC_INLINE uintptr_t from_stream(::FILE *f) { + if (f == stdin) + return reinterpret_cast<uintptr_t>(f) | Stdin; + if (f == stdout) + return reinterpret_cast<uintptr_t>(f) | Stdout; + if (f == stderr) + return reinterpret_cast<uintptr_t>(f) | Stderr; + return reinterpret_cast<uintptr_t>(f); +} + +// Get the associated stream out of an encoded number. +LIBC_INLINE ::FILE *to_stream(uintptr_t f) { + ::FILE *stream = reinterpret_cast<FILE *>(f & ~0x3ull); + Stream type = static_cast<Stream>(f & 0x3ull); + if (type == Stdin) + return stdin; + if (type == Stdout) + return stdout; + if (type == Stderr) + return stderr; + return stream; +} + } // namespace file } // namespace __llvm_libc diff --git a/libc/src/stdio/gpu/getc.cpp b/libc/src/stdio/gpu/getc.cpp new file mode 100644 index 000000000000..a2272221d6b7 --- /dev/null +++ b/libc/src/stdio/gpu/getc.cpp @@ -0,0 +1,25 @@ +//===-- GPU implementation of getc ----------------------------------------===// +// +// 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/getc.h" +#include "file.h" + +#include <stdio.h> + +namespace __llvm_libc { + +LLVM_LIBC_FUNCTION(int, getc, (::FILE * stream)) { + unsigned char c; + size_t r = file::read(stream, &c, 1); + + if (r != 1) + return EOF; + return c; +} + +} // namespace __llvm_libc diff --git a/libc/src/stdio/gpu/getchar.cpp b/libc/src/stdio/gpu/getchar.cpp new file mode 100644 index 000000000000..a7a6e6c55c13 --- /dev/null +++ b/libc/src/stdio/gpu/getchar.cpp @@ -0,0 +1,25 @@ +//===-- GPU implementation of getchar -------------------------------------===// +// +// 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/getchar.h" +#include "file.h" + +#include <stdio.h> + +namespace __llvm_libc { + +LLVM_LIBC_FUNCTION(int, getchar, ()) { + unsigned char c; + size_t r = file::read(stdin, &c, 1); + + if (r != 1) + return EOF; + return c; +} + +} // namespace __llvm_libc |
