[libc-commits] [libc] [libc] Implement stdio writing functions for the GPU port (PR #65809)

Joseph Huber via libc-commits libc-commits at lists.llvm.org
Fri Sep 8 14:19:56 PDT 2023


https://github.com/jhuber6 created https://github.com/llvm/llvm-project/pull/65809:

Summary:
This patch implements fwrite, putc, putchar, and fputc on the GPU. These
are very straightforward, the main difference for the GPU implementation
is that we are currently ignoring `errno`. This patch also introduces a
minimal smoke test for `putc` that is an exact copy of the `puts` test
except we print the string char by char. This also modifies the `fopen`
test to use `fwrite` to mirror its use of `fread` so that it is tested
as well.


>From fcbc773bbf5442cb45eae92f69cad119a952283e Mon Sep 17 00:00:00 2001
From: Joseph Huber <jhuber6 at vols.utk.edu>
Date: Fri, 8 Sep 2023 16:11:47 -0500
Subject: [PATCH] [libc] Implement stdio writing functions for the GPU port

Summary:
This patch implements fwrite, putc, putchar, and fputc on the GPU. These
are very straightforward, the main difference for the GPU implementation
is that we are currently ignoring `errno`. This patch also introduces a
minimal smoke test for `putc` that is an exact copy of the `puts` test
except we print the string char by char. This also modifies the `fopen`
test to use `fwrite` to mirror its use of `fread` so that it is tested
as well.
---
 libc/config/gpu/entrypoints.txt               |  4 ++
 libc/docs/gpu/support.rst                     |  8 ++-
 libc/src/stdio/CMakeLists.txt                 | 70 ++-----------------
 libc/src/stdio/generic/CMakeLists.txt         | 65 +++++++++++++++++
 libc/src/stdio/{ => generic}/fputc.cpp        |  0
 libc/src/stdio/{ => generic}/fwrite.cpp       |  0
 .../stdio/{ => generic}/fwrite_unlocked.cpp   |  0
 libc/src/stdio/{ => generic}/putc.cpp         |  0
 libc/src/stdio/{ => generic}/putchar.cpp      |  0
 libc/src/stdio/gpu/CMakeLists.txt             | 44 ++++++++++++
 libc/src/stdio/gpu/fputc.cpp                  | 26 +++++++
 libc/src/stdio/gpu/fwrite.cpp                 | 26 +++++++
 libc/src/stdio/gpu/putc.cpp                   | 26 +++++++
 libc/src/stdio/gpu/putchar.cpp                | 26 +++++++
 libc/test/src/stdio/CMakeLists.txt            | 16 ++++-
 libc/test/src/stdio/fopen_test.cpp            |  4 +-
 libc/test/src/stdio/fputc_test.cpp            | 30 ++++++++
 17 files changed, 275 insertions(+), 70 deletions(-)
 rename libc/src/stdio/{ => generic}/fputc.cpp (100%)
 rename libc/src/stdio/{ => generic}/fwrite.cpp (100%)
 rename libc/src/stdio/{ => generic}/fwrite_unlocked.cpp (100%)
 rename libc/src/stdio/{ => generic}/putc.cpp (100%)
 rename libc/src/stdio/{ => generic}/putchar.cpp (100%)
 create mode 100644 libc/src/stdio/gpu/fputc.cpp
 create mode 100644 libc/src/stdio/gpu/fwrite.cpp
 create mode 100644 libc/src/stdio/gpu/putc.cpp
 create mode 100644 libc/src/stdio/gpu/putchar.cpp
 create mode 100644 libc/test/src/stdio/fputc_test.cpp

diff --git a/libc/config/gpu/entrypoints.txt b/libc/config/gpu/entrypoints.txt
index bf59ba6b0a3eaa6..0e314c60870c6ae 100644
--- a/libc/config/gpu/entrypoints.txt
+++ b/libc/config/gpu/entrypoints.txt
@@ -88,6 +88,10 @@ set(TARGET_LIBC_ENTRYPOINTS
     libc.src.stdio.fclose
     libc.src.stdio.fread
     libc.src.stdio.fputs
+    libc.src.stdio.fwrite
+    libc.src.stdio.fputc
+    libc.src.stdio.putc
+    libc.src.stdio.putchar
     libc.src.stdio.stdin
     libc.src.stdio.stdout
     libc.src.stdio.stderr
diff --git a/libc/docs/gpu/support.rst b/libc/docs/gpu/support.rst
index 3e8de03050332d1..fabdfb968a741ad 100644
--- a/libc/docs/gpu/support.rst
+++ b/libc/docs/gpu/support.rst
@@ -118,20 +118,24 @@ strtoumax      |check|
 =============  =========  ============
 
 stdio.h
---------
+-------
 
 =============  =========  ============
 Function Name  Available  RPC Required
 =============  =========  ============
 puts           |check|    |check|
 fputs          |check|    |check|
+fputc          |check|    |check|
+fwrite         |check|    |check|
+putc           |check|    |check|
+putchar        |check|    |check|
 fclose         |check|    |check|
 fopen          |check|    |check|
 fread          |check|    |check|
 =============  =========  ============
 
 time.h
---------
+------
 
 =============  =========  ============
 Function Name  Available  RPC Required
diff --git a/libc/src/stdio/CMakeLists.txt b/libc/src/stdio/CMakeLists.txt
index 79863f83c1e5e7d..740ec106da2e4d7 100644
--- a/libc/src/stdio/CMakeLists.txt
+++ b/libc/src/stdio/CMakeLists.txt
@@ -229,71 +229,6 @@ add_entrypoint_object(
     libc.src.__support.File.platform_file
 )
 
-add_entrypoint_object(
-  fwrite_unlocked
-  SRCS
-    fwrite_unlocked.cpp
-  HDRS
-    fwrite_unlocked.h
-  DEPENDS
-    libc.src.errno.errno
-    libc.include.stdio
-    libc.src.__support.File.file
-    libc.src.__support.File.platform_file
-)
-
-add_entrypoint_object(
-  fwrite
-  SRCS
-    fwrite.cpp
-  HDRS
-    fwrite.h
-  DEPENDS
-    libc.src.errno.errno
-    libc.include.stdio
-    libc.src.__support.File.file
-    libc.src.__support.File.platform_file
-)
-
-add_entrypoint_object(
-  fputc
-  SRCS
-    fputc.cpp
-  HDRS
-    fputc.h
-  DEPENDS
-    libc.src.errno.errno
-    libc.include.stdio
-    libc.src.__support.File.file
-    libc.src.__support.File.platform_file
-)
-
-add_entrypoint_object(
-  putc
-  SRCS
-    putc.cpp
-  HDRS
-    putc.h
-  DEPENDS
-    libc.src.errno.errno
-    libc.include.stdio
-    libc.src.__support.File.file
-    libc.src.__support.File.platform_file
-)
-
-add_entrypoint_object(
-  putchar
-  SRCS
-    putchar.cpp
-  HDRS
-    putchar.h
-  DEPENDS
-    libc.src.errno.errno
-    libc.include.stdio
-    libc.src.__support.File.file
-    libc.src.__support.File.platform_file
-)
-
 add_entrypoint_object(
   fseek
   SRCS
@@ -538,6 +473,11 @@ add_stdio_entrypoint_object(fread_unlocked)
 add_stdio_entrypoint_object(fread)
 add_stdio_entrypoint_object(puts)
 add_stdio_entrypoint_object(fputs)
+add_stdio_entrypoint_object(fwrite_unlocked)
+add_stdio_entrypoint_object(fwrite)
+add_stdio_entrypoint_object(fputc)
+add_stdio_entrypoint_object(putc)
+add_stdio_entrypoint_object(putchar)
 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 8d14d9fbf6f2497..e40e2cc9e04d3e3 100644
--- a/libc/src/stdio/generic/CMakeLists.txt
+++ b/libc/src/stdio/generic/CMakeLists.txt
@@ -75,6 +75,71 @@ add_entrypoint_object(
     libc.src.__support.File.platform_stdout
 )
 
+add_entrypoint_object(
+  fwrite_unlocked
+  SRCS
+    fwrite_unlocked.cpp
+  HDRS
+    ../fwrite_unlocked.h
+  DEPENDS
+    libc.src.errno.errno
+    libc.include.stdio
+    libc.src.__support.File.file
+    libc.src.__support.File.platform_file
+)
+
+add_entrypoint_object(
+  fwrite
+  SRCS
+    fwrite.cpp
+  HDRS
+    ../fwrite.h
+  DEPENDS
+    libc.src.errno.errno
+    libc.include.stdio
+    libc.src.__support.File.file
+    libc.src.__support.File.platform_file
+)
+
+add_entrypoint_object(
+  fputc
+  SRCS
+    fputc.cpp
+  HDRS
+    ../fputc.h
+  DEPENDS
+    libc.src.errno.errno
+    libc.include.stdio
+    libc.src.__support.File.file
+    libc.src.__support.File.platform_file
+)
+
+add_entrypoint_object(
+  putc
+  SRCS
+    putc.cpp
+  HDRS
+    ../putc.h
+  DEPENDS
+    libc.src.errno.errno
+    libc.include.stdio
+    libc.src.__support.File.file
+    libc.src.__support.File.platform_file
+)
+
+add_entrypoint_object(
+  putchar
+  SRCS
+    putchar.cpp
+  HDRS
+    ../putchar.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/fputc.cpp b/libc/src/stdio/generic/fputc.cpp
similarity index 100%
rename from libc/src/stdio/fputc.cpp
rename to libc/src/stdio/generic/fputc.cpp
diff --git a/libc/src/stdio/fwrite.cpp b/libc/src/stdio/generic/fwrite.cpp
similarity index 100%
rename from libc/src/stdio/fwrite.cpp
rename to libc/src/stdio/generic/fwrite.cpp
diff --git a/libc/src/stdio/fwrite_unlocked.cpp b/libc/src/stdio/generic/fwrite_unlocked.cpp
similarity index 100%
rename from libc/src/stdio/fwrite_unlocked.cpp
rename to libc/src/stdio/generic/fwrite_unlocked.cpp
diff --git a/libc/src/stdio/putc.cpp b/libc/src/stdio/generic/putc.cpp
similarity index 100%
rename from libc/src/stdio/putc.cpp
rename to libc/src/stdio/generic/putc.cpp
diff --git a/libc/src/stdio/putchar.cpp b/libc/src/stdio/generic/putchar.cpp
similarity index 100%
rename from libc/src/stdio/putchar.cpp
rename to libc/src/stdio/generic/putchar.cpp
diff --git a/libc/src/stdio/gpu/CMakeLists.txt b/libc/src/stdio/gpu/CMakeLists.txt
index 458dd86175021c4..d35b1925c6a47a0 100644
--- a/libc/src/stdio/gpu/CMakeLists.txt
+++ b/libc/src/stdio/gpu/CMakeLists.txt
@@ -61,6 +61,50 @@ add_entrypoint_object(
     .gpu_file
 )
 
+add_entrypoint_object(
+  fwrite
+  SRCS
+    fwrite.cpp
+  HDRS
+    ../fwrite.h
+  DEPENDS
+    libc.include.stdio
+    .gpu_file
+)
+
+add_entrypoint_object(
+  fputc
+  SRCS
+    fputc.cpp
+  HDRS
+    ../fputc.h
+  DEPENDS
+    libc.include.stdio
+    .gpu_file
+)
+
+add_entrypoint_object(
+  putc
+  SRCS
+    putc.cpp
+  HDRS
+    ../putc.h
+  DEPENDS
+    libc.include.stdio
+    .gpu_file
+)
+
+add_entrypoint_object(
+  putchar
+  SRCS
+    putchar.cpp
+  HDRS
+    ../putchar.h
+  DEPENDS
+    libc.include.stdio
+    .gpu_file
+)
+
 add_entrypoint_object(
   stdin
   SRCS
diff --git a/libc/src/stdio/gpu/fputc.cpp b/libc/src/stdio/gpu/fputc.cpp
new file mode 100644
index 000000000000000..90d238972972ec0
--- /dev/null
+++ b/libc/src/stdio/gpu/fputc.cpp
@@ -0,0 +1,26 @@
+//===-- GPU implementation of fputc ---------------------------------------===//
+//
+// 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 "file.h"
+#include "src/stdio/fputc.h"
+
+#include <stdio.h>
+
+namespace __llvm_libc {
+
+LLVM_LIBC_FUNCTION(int, fputc, (int c, ::FILE *stream)) {
+  unsigned char uc = static_cast<unsigned char>(c);
+
+  size_t written = file::write(stream, &uc, 1);
+  if (1 != written)
+    return EOF;
+
+  return 0;
+}
+
+} // namespace __llvm_libc
diff --git a/libc/src/stdio/gpu/fwrite.cpp b/libc/src/stdio/gpu/fwrite.cpp
new file mode 100644
index 000000000000000..fccaabd0673ec5c
--- /dev/null
+++ b/libc/src/stdio/gpu/fwrite.cpp
@@ -0,0 +1,26 @@
+//===-- GPU implementation of fwrite --------------------------------------===//
+//
+// 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/fwrite.h"
+#include "file.h"
+
+#include <stdio.h>
+
+namespace __llvm_libc {
+
+LLVM_LIBC_FUNCTION(size_t, fwrite,
+                   (const void *__restrict buffer, size_t size, size_t nmemb,
+                    ::FILE *stream)) {
+  if (size == 0 || nmemb == 0)
+    return 0;
+
+  auto result = file::write(stream, buffer, size * nmemb);
+  return result / size;
+}
+
+} // namespace __llvm_libc
diff --git a/libc/src/stdio/gpu/putc.cpp b/libc/src/stdio/gpu/putc.cpp
new file mode 100644
index 000000000000000..d450edb6596df1c
--- /dev/null
+++ b/libc/src/stdio/gpu/putc.cpp
@@ -0,0 +1,26 @@
+//===-- GPU implementation of putc ----------------------------------------===//
+//
+// 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/putc.h"
+#include "file.h"
+
+#include <stdio.h>
+
+namespace __llvm_libc {
+
+LLVM_LIBC_FUNCTION(int, putc, (int c, ::FILE *stream)) {
+  unsigned char uc = static_cast<unsigned char>(c);
+
+  size_t written = file::write(stream, &uc, 1);
+  if (1 != written)
+    return EOF;
+
+  return 0;
+}
+
+} // namespace __llvm_libc
diff --git a/libc/src/stdio/gpu/putchar.cpp b/libc/src/stdio/gpu/putchar.cpp
new file mode 100644
index 000000000000000..df577544b8ba405
--- /dev/null
+++ b/libc/src/stdio/gpu/putchar.cpp
@@ -0,0 +1,26 @@
+//===-- GPU implementation of putchar -------------------------------------===//
+//
+// 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 "file.h"
+#include "src/stdio/putchar.h"
+
+#include <stdio.h>
+
+namespace __llvm_libc {
+
+LLVM_LIBC_FUNCTION(int, putchar, (int c)) {
+  unsigned char uc = static_cast<unsigned char>(c);
+
+  size_t written = file::write(stdout, &uc, 1);
+  if (1 != written)
+    return EOF;
+
+  return 0;
+}
+
+} // namespace __llvm_libc
diff --git a/libc/test/src/stdio/CMakeLists.txt b/libc/test/src/stdio/CMakeLists.txt
index 01590f9acb8545f..6090dc1f46c87ef 100644
--- a/libc/test/src/stdio/CMakeLists.txt
+++ b/libc/test/src/stdio/CMakeLists.txt
@@ -271,6 +271,20 @@ add_libc_test(
     libc.src.stdio.stderr
 )
 
+add_libc_test(
+  fputc_test
+  HERMETIC_TEST_ONLY # writes to libc's stdout and stderr
+  SUITE
+    libc_stdio_unittests
+  SRCS
+    fputc_test.cpp
+  DEPENDS
+    libc.src.stdio.fputc
+    libc.src.stdio.putchar
+    libc.src.stdio.stdout
+    libc.src.stdio.stderr
+)
+
 add_libc_test(
   fopen_test
   SUITE
@@ -279,7 +293,7 @@ add_libc_test(
     fopen_test.cpp
   DEPENDS
     libc.src.stdio.fread
-    libc.src.stdio.fputs
+    libc.src.stdio.fwrite
     libc.src.stdio.fclose
     libc.src.stdio.fopen
 )
diff --git a/libc/test/src/stdio/fopen_test.cpp b/libc/test/src/stdio/fopen_test.cpp
index 8e8a1c9638f5be6..f0de8caf673cc7e 100644
--- a/libc/test/src/stdio/fopen_test.cpp
+++ b/libc/test/src/stdio/fopen_test.cpp
@@ -9,7 +9,7 @@
 #include "src/__support/File/file.h"
 #include "src/stdio/fclose.h"
 #include "src/stdio/fopen.h"
-#include "src/stdio/fputs.h"
+#include "src/stdio/fwrite.h"
 #include "src/stdio/fread.h"
 
 #include "test/UnitTest/Test.h"
@@ -21,7 +21,7 @@ TEST(LlvmLibcFOpenTest, PrintToFile) {
   ASSERT_FALSE(file == nullptr);
 
   static constexpr char STRING[] = "A simple string written to a file\n";
-  result = __llvm_libc::fputs(STRING, file);
+  result = __llvm_libc::fwrite(STRING, 1, sizeof(STRING) - 1, file);
   EXPECT_GE(result, 0);
 
   ASSERT_EQ(0, __llvm_libc::fclose(file));
diff --git a/libc/test/src/stdio/fputc_test.cpp b/libc/test/src/stdio/fputc_test.cpp
new file mode 100644
index 000000000000000..e5aa7c713463bf2
--- /dev/null
+++ b/libc/test/src/stdio/fputc_test.cpp
@@ -0,0 +1,30 @@
+//===-- Unittests for fputc / putchar -------------------------------------===//
+//
+// 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/File/file.h"
+#include "src/stdio/fputc.h"
+#include "src/stdio/putchar.h"
+
+#include "test/UnitTest/Test.h"
+
+TEST(LlvmLibcPutcTest, PrintOut) {
+  int result;
+
+  constexpr char simple[] = "A simple string written to stdout\n";
+  for (const char &c : simple) {
+    result = __llvm_libc::putchar(c);
+    EXPECT_GE(result, 0);
+  }
+
+  constexpr char more[] = "A simple string written to stderr\n";
+  for (const char &c : simple) {
+    result =
+        __llvm_libc::fputc(c, reinterpret_cast<FILE *>(__llvm_libc::stderr));
+  }
+  EXPECT_GE(result, 0);
+}



More information about the libc-commits mailing list