summaryrefslogtreecommitdiff
path: root/libc/src/stdio/gpu
diff options
context:
space:
mode:
authorJoseph Huber <35342157+jhuber6@users.noreply.github.com>2023-09-14 15:39:29 -0500
committerGitHub <noreply@github.com>2023-09-14 15:39:29 -0500
commita1be5d69dff0ff9bdf0329370a3ce724bcd25ed2 (patch)
tree4d6c93caba191693578233d95392351a7d9f9409 /libc/src/stdio/gpu
parent96ccc81fb8bbe6a545d52c79cc66ae614241b0a4 (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.txt113
-rw-r--r--libc/src/stdio/gpu/clearerr.cpp24
-rw-r--r--libc/src/stdio/gpu/feof.cpp26
-rw-r--r--libc/src/stdio/gpu/ferror.cpp26
-rw-r--r--libc/src/stdio/gpu/fgetc.cpp25
-rw-r--r--libc/src/stdio/gpu/fgets.cpp46
-rw-r--r--libc/src/stdio/gpu/file.h33
-rw-r--r--libc/src/stdio/gpu/getc.cpp25
-rw-r--r--libc/src/stdio/gpu/getchar.cpp25
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