Skip to content

[libc] Implement more input functions on the GPU #66288

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

Merged
merged 4 commits into from
Sep 14, 2023

Conversation

jhuber6
Copy link
Contributor

@jhuber6 jhuber6 commented Sep 13, 2023

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.

@jhuber6 jhuber6 requested a review from a team as a code owner September 13, 2023 20:37
@llvmbot llvmbot added the libc label Sep 13, 2023
@llvmbot
Copy link
Member

llvmbot commented Sep 13, 2023

@llvm/pr-subscribers-libc

Changes 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.

--
Full diff: https://github.com/llvm/llvm-project/pull/66288.diff

16 Files Affected:

  • (modified) libc/config/gpu/entrypoints.txt (+4)
  • (modified) libc/src/stdio/CMakeLists.txt (+7-91)
  • (modified) libc/src/stdio/generic/CMakeLists.txt (+91)
  • (renamed) libc/src/stdio/generic/fgetc.cpp ()
  • (renamed) libc/src/stdio/generic/fgetc_unlocked.cpp ()
  • (renamed) libc/src/stdio/generic/fgets.cpp ()
  • (renamed) libc/src/stdio/generic/getc.cpp ()
  • (renamed) libc/src/stdio/generic/getc_unlocked.cpp ()
  • (renamed) libc/src/stdio/generic/getchar.cpp ()
  • (renamed) libc/src/stdio/generic/getchar_unlocked.cpp ()
  • (modified) libc/src/stdio/gpu/CMakeLists.txt (+77)
  • (added) libc/src/stdio/gpu/fgetc.cpp (+25)
  • (added) libc/src/stdio/gpu/fgets.cpp (+42)
  • (added) libc/src/stdio/gpu/getc.cpp (+25)
  • (added) libc/src/stdio/gpu/getchar.cpp (+25)
  • (modified) libc/test/src/stdio/CMakeLists.txt (+2-2)
diff --git a/libc/config/gpu/entrypoints.txt b/libc/config/gpu/entrypoints.txt
index b8d09c9bb8a8bde..26b944c44e01580 100644
--- a/libc/config/gpu/entrypoints.txt
+++ b/libc/config/gpu/entrypoints.txt
@@ -95,6 +95,10 @@ set(TARGET_LIBC_ENTRYPOINTS
     libc.src.stdio.fputc
     libc.src.stdio.putc
     libc.src.stdio.putchar
+    libc.src.stdio.fgets
+    libc.src.stdio.fgetc
+    libc.src.stdio.getc
+    libc.src.stdio.getchar
     libc.src.stdio.stdin
     libc.src.stdio.stdout
     libc.src.stdio.stderr
diff --git a/libc/src/stdio/CMakeLists.txt b/libc/src/stdio/CMakeLists.txt
index de28b5c02071bf7..0778bb27555f796 100644
--- a/libc/src/stdio/CMakeLists.txt
+++ b/libc/src/stdio/CMakeLists.txt
@@ -101,97 +101,6 @@ add_entrypoint_object(
     libc.src.__support.File.platform_file
 )
 
-add_entrypoint_object(
-  fgetc
-  SRCS
-    fgetc.cpp
-  HDRS
-    fgetc.h
-  DEPENDS
-    libc.src.errno.errno
-    libc.include.stdio
-    libc.src.__support.File.file
-    libc.src.__support.File.platform_file
-)
-
-add_entrypoint_object(
-  fgetc_unlocked
-  SRCS
-    fgetc_unlocked.cpp
-  HDRS
-    fgetc_unlocked.h
-  DEPENDS
-    libc.src.errno.errno
-    libc.include.stdio
-    libc.src.__support.File.file
-    libc.src.__support.File.platform_file
-)
-
-add_entrypoint_object(
-  getc
-  SRCS
-    getc.cpp
-  HDRS
-    getc.h
-  DEPENDS
-    libc.src.errno.errno
-    libc.include.stdio
-    libc.src.__support.File.file
-    libc.src.__support.File.platform_file
-)
-
-add_entrypoint_object(
-  getc_unlocked
-  SRCS
-    getc_unlocked.cpp
-  HDRS
-    getc_unlocked.h
-  DEPENDS
-    libc.src.errno.errno
-    libc.include.stdio
-    libc.src.__support.File.file
-    libc.src.__support.File.platform_file
-)
-
-add_entrypoint_object(
-  getchar
-  SRCS
-    getchar.cpp
-  HDRS
-    getchar.h
-  DEPENDS
-    libc.src.errno.errno
-    libc.include.stdio
-    libc.src.__support.File.file
-    libc.src.__support.File.platform_file
-)
-
-add_entrypoint_object(
-  getchar_unlocked
-  SRCS
-    getc_unlocked.cpp
-  HDRS
-    getc_unlocked.h
-  DEPENDS
-    libc.src.errno.errno
-    libc.include.stdio
-    libc.src.__support.File.file
-    libc.src.__support.File.platform_file
-)
-
-add_entrypoint_object(
-  fgets
-  SRCS
-    fgets.cpp
-  HDRS
-    fgets.h
-  DEPENDS
-    libc.src.errno.errno
-    libc.include.stdio
-    libc.src.__support.File.file
-    libc.src.__support.File.platform_file
-)
-
 add_entrypoint_object(
   fflush
   SRCS
@@ -481,6 +390,13 @@ add_stdio_entrypoint_object(fwrite)
 add_stdio_entrypoint_object(fputc)
 add_stdio_entrypoint_object(putc)
 add_stdio_entrypoint_object(putchar)
+add_stdio_entrypoint_object(fgetc)
+add_stdio_entrypoint_object(fgetc_unlocked)
+add_stdio_entrypoint_object(getc)
+add_stdio_entrypoint_object(getc_unlocked)
+add_stdio_entrypoint_object(getchar)
+add_stdio_entrypoint_object(getchar_unlocked)
+add_stdio_entrypoint_object(fgets)
 add_stdio_entrypoint_object(stdin)
 add_stdio_entrypoint_object(stdout)
 add_stdio_entrypoint_object(stderr)
diff --git a/libc/src/stdio/generic/CMakeLists.txt b/libc/src/stdio/generic/CMakeLists.txt
index e40e2cc9e04d3e3..e4047649097f622 100644
--- a/libc/src/stdio/generic/CMakeLists.txt
+++ b/libc/src/stdio/generic/CMakeLists.txt
@@ -140,6 +140,97 @@ add_entrypoint_object(
     libc.src.__support.File.platform_file
 )
 
+add_entrypoint_object(
+  fgetc
+  SRCS
+    fgetc.cpp
+  HDRS
+    ../fgetc.h
+  DEPENDS
+    libc.src.errno.errno
+    libc.include.stdio
+    libc.src.__support.File.file
+    libc.src.__support.File.platform_file
+)
+
+add_entrypoint_object(
+  fgetc_unlocked
+  SRCS
+    fgetc_unlocked.cpp
+  HDRS
+    ../fgetc_unlocked.h
+  DEPENDS
+    libc.src.errno.errno
+    libc.include.stdio
+    libc.src.__support.File.file
+    libc.src.__support.File.platform_file
+)
+
+add_entrypoint_object(
+  getc
+  SRCS
+    getc.cpp
+  HDRS
+    ../getc.h
+  DEPENDS
+    libc.src.errno.errno
+    libc.include.stdio
+    libc.src.__support.File.file
+    libc.src.__support.File.platform_file
+)
+
+add_entrypoint_object(
+  getc_unlocked
+  SRCS
+    getc_unlocked.cpp
+  HDRS
+    ../getc_unlocked.h
+  DEPENDS
+    libc.src.errno.errno
+    libc.include.stdio
+    libc.src.__support.File.file
+    libc.src.__support.File.platform_file
+)
+
+add_entrypoint_object(
+  getchar
+  SRCS
+    getchar.cpp
+  HDRS
+    ../getchar.h
+  DEPENDS
+    libc.src.errno.errno
+    libc.include.stdio
+    libc.src.__support.File.file
+    libc.src.__support.File.platform_file
+)
+
+add_entrypoint_object(
+  getchar_unlocked
+  SRCS
+    getc_unlocked.cpp
+  HDRS
+    ../getc_unlocked.h
+  DEPENDS
+    libc.src.errno.errno
+    libc.include.stdio
+    libc.src.__support.File.file
+    libc.src.__support.File.platform_file
+)
+
+add_entrypoint_object(
+  fgets
+  SRCS
+    fgets.cpp
+  HDRS
+    ../fgets.h
+  DEPENDS
+    libc.src.errno.errno
+    libc.include.stdio
+    libc.src.__support.File.file
+    libc.src.__support.File.platform_file
+)
+
 add_entrypoint_object(
   stdin
   SRCS
diff --git a/libc/src/stdio/fgetc.cpp b/libc/src/stdio/generic/fgetc.cpp
similarity index 100%
rename from libc/src/stdio/fgetc.cpp
rename to libc/src/stdio/generic/fgetc.cpp
diff --git a/libc/src/stdio/fgetc_unlocked.cpp b/libc/src/stdio/generic/fgetc_unlocked.cpp
similarity index 100%
rename from libc/src/stdio/fgetc_unlocked.cpp
rename to libc/src/stdio/generic/fgetc_unlocked.cpp
diff --git a/libc/src/stdio/fgets.cpp b/libc/src/stdio/generic/fgets.cpp
similarity index 100%
rename from libc/src/stdio/fgets.cpp
rename to libc/src/stdio/generic/fgets.cpp
diff --git a/libc/src/stdio/getc.cpp b/libc/src/stdio/generic/getc.cpp
similarity index 100%
rename from libc/src/stdio/getc.cpp
rename to libc/src/stdio/generic/getc.cpp
diff --git a/libc/src/stdio/getc_unlocked.cpp b/libc/src/stdio/generic/getc_unlocked.cpp
similarity index 100%
rename from libc/src/stdio/getc_unlocked.cpp
rename to libc/src/stdio/generic/getc_unlocked.cpp
diff --git a/libc/src/stdio/getchar.cpp b/libc/src/stdio/generic/getchar.cpp
similarity index 100%
rename from libc/src/stdio/getchar.cpp
rename to libc/src/stdio/generic/getchar.cpp
diff --git a/libc/src/stdio/getchar_unlocked.cpp b/libc/src/stdio/generic/getchar_unlocked.cpp
similarity index 100%
rename from libc/src/stdio/getchar_unlocked.cpp
rename to libc/src/stdio/generic/getchar_unlocked.cpp
diff --git a/libc/src/stdio/gpu/CMakeLists.txt b/libc/src/stdio/gpu/CMakeLists.txt
index d35b1925c6a47a0..139ef2e77fe28cc 100644
--- a/libc/src/stdio/gpu/CMakeLists.txt
+++ b/libc/src/stdio/gpu/CMakeLists.txt
@@ -105,6 +105,83 @@ add_entrypoint_object(
     .gpu_file
 )
 
+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
+)
+
 add_entrypoint_object(
   stdin
   SRCS
diff --git a/libc/src/stdio/gpu/fgetc.cpp b/libc/src/stdio/gpu/fgetc.cpp
new file mode 100644
index 000000000000000..ff4ef27ccb88e9a
--- /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 000000000000000..b696d2731b984a5
--- /dev/null
+++ b/libc/src/stdio/gpu/fgets.cpp
@@ -0,0 +1,42 @@
+//===-- 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 <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;
+
+  unsigned char c = '\0';
+  int i;
+  for (i = 0; i < (count - 1) && c != '\n'; ++i) {
+    auto r = file::read(stream, &c, 1);
+    if (r != 1)
+      return nullptr;
+
+    str[i] = c;
+  }
+
+  // If the requested read size makes no sense, an error occured, or no bytes
+  // were read due to an EOF, then return nullptr and don't write the null byte.
+  if (i == 0)
+    return nullptr;
+
+  str[i] = '\0';
+  return str;
+}
+
+} // namespace __llvm_libc
diff --git a/libc/src/stdio/gpu/getc.cpp b/libc/src/stdio/gpu/getc.cpp
new file mode 100644
index 000000000000000..a2272221d6b7b92
--- /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 000000000000000..a7a6e6c55c13e1a
--- /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
diff --git a/libc/test/src/stdio/CMakeLists.txt b/libc/test/src/stdio/CMakeLists.txt
index 6090dc1f46c87ef..c4f0e86aa6f993a 100644
--- a/libc/test/src/stdio/CMakeLists.txt
+++ b/libc/test/src/stdio/CMakeLists.txt
@@ -330,7 +330,7 @@ if(${LIBC_TARGET_OS} STREQUAL "linux")
   )
 endif()
 
-add_libc_unittest(
+add_libc_test(
   fgetc_test
   SUITE
     libc_stdio_unittests
@@ -370,7 +370,7 @@ add_libc_unittest(
     libc.src.stdio.getc_unlocked
 )
 
-add_libc_unittest(
+add_libc_test(
   fgets_test
   SUITE
     libc_stdio_unittests

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.
Copy link
Collaborator

@sivachandra sivachandra left a comment

Choose a reason for hiding this comment

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

OK for non-GPU changes.

Summary:
When crossing the device boundary we will find that the standard stream
have different pointers. This is intentional as it allows us to perform
IO on the standard streams without first needing to do any setup.
However, this needs to be accounted for in the implementation. This
patch adds some logic to  encode whether or not this is a standard
stream in the low orders of the bits. Because these are aligned to at
least a 4 bytes boundary we will always have access to 2 bits to store 4
different values.
@jhuber6 jhuber6 merged commit a1be5d6 into llvm:main Sep 14, 2023
ZijunZhaoCCK pushed a commit to ZijunZhaoCCK/llvm-project that referenced this pull request Sep 19, 2023
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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants