Skip to content

Commit ddc30ff

Browse files
authored
[libc] Implement the 'ungetc' function on the GPU (#69248)
Summary: This function follows closely with the pattern of all the other functions. That is, making a new opcode and forwarding the call to the host. However, this also required modifying the test somewhat. It seems that not all `libc` implementations follow the same error rules as are tested here, and it is not explicit in the standard, so we simply disable these EOF checks when targeting the GPU.
1 parent 761c9dd commit ddc30ff

File tree

10 files changed

+71
-12
lines changed

10 files changed

+71
-12
lines changed

libc/config/gpu/entrypoints.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ set(TARGET_LIBC_ENTRYPOINTS
104104
libc.src.stdio.fgetc
105105
libc.src.stdio.getc
106106
libc.src.stdio.getchar
107+
libc.src.stdio.ungetc
107108
libc.src.stdio.stdin
108109
libc.src.stdio.stdout
109110
libc.src.stdio.stderr

libc/docs/gpu/support.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@ ftell |check| |check|
134134
fflush |check| |check|
135135
fgetc |check| |check|
136136
fgets |check| |check|
137+
ungetc |check| |check|
137138
getc |check| |check|
138139
getchar |check| |check|
139140
puts |check| |check|

libc/include/llvm-libc-types/rpc_opcodes_t.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ typedef enum {
2929
RPC_FSEEK,
3030
RPC_FTELL,
3131
RPC_FFLUSH,
32+
RPC_UNGETC,
3233
RPC_LAST = 0xFFFF,
3334
} rpc_opcode_t;
3435

libc/src/stdio/CMakeLists.txt

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -54,18 +54,6 @@ add_entrypoint_object(
5454
libc.src.__support.File.platform_file
5555
)
5656

57-
add_entrypoint_object(
58-
ungetc
59-
SRCS
60-
ungetc.cpp
61-
HDRS
62-
ungetc.h
63-
DEPENDS
64-
libc.include.stdio
65-
libc.src.__support.File.file
66-
libc.src.__support.File.platform_file
67-
)
68-
6957
add_entrypoint_object(
7058
fopencookie
7159
SRCS
@@ -286,6 +274,7 @@ add_stdio_entrypoint_object(getc_unlocked)
286274
add_stdio_entrypoint_object(getchar)
287275
add_stdio_entrypoint_object(getchar_unlocked)
288276
add_stdio_entrypoint_object(fgets)
277+
add_stdio_entrypoint_object(ungetc)
289278
add_stdio_entrypoint_object(stdin)
290279
add_stdio_entrypoint_object(stdout)
291280
add_stdio_entrypoint_object(stderr)

libc/src/stdio/generic/CMakeLists.txt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,18 @@ add_entrypoint_object(
342342
libc.src.__support.File.platform_file
343343
)
344344

345+
add_entrypoint_object(
346+
ungetc
347+
SRCS
348+
ungetc.cpp
349+
HDRS
350+
../ungetc.h
351+
DEPENDS
352+
libc.include.stdio
353+
libc.src.__support.File.file
354+
libc.src.__support.File.platform_file
355+
)
356+
345357
add_entrypoint_object(
346358
stdin
347359
SRCS
File renamed without changes.

libc/src/stdio/gpu/CMakeLists.txt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,17 @@ add_entrypoint_object(
251251
.ferror
252252
)
253253

254+
add_entrypoint_object(
255+
ungetc
256+
SRCS
257+
ungetc.cpp
258+
HDRS
259+
../ungetc.h
260+
DEPENDS
261+
libc.include.stdio
262+
.gpu_file
263+
)
264+
254265
add_entrypoint_object(
255266
stdin
256267
SRCS

libc/src/stdio/gpu/ungetc.cpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
//===-- Implementation of ungetc ------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "src/stdio/ungetc.h"
10+
#include "file.h"
11+
12+
#include <stdio.h>
13+
14+
namespace LIBC_NAMESPACE {
15+
16+
LLVM_LIBC_FUNCTION(int, ungetc, (int c, ::FILE *stream)) {
17+
int ret;
18+
rpc::Client::Port port = rpc::client.open<RPC_UNGETC>();
19+
port.send_and_recv(
20+
[=](rpc::Buffer *buffer) {
21+
buffer->data[0] = c;
22+
buffer->data[1] = file::from_stream(stream);
23+
},
24+
[&](rpc::Buffer *buffer) { ret = static_cast<int>(buffer->data[0]); });
25+
port.close();
26+
return ret;
27+
}
28+
29+
} // namespace LIBC_NAMESPACE

libc/test/src/stdio/ungetc_test.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,16 @@ TEST(LlvmLibcUngetcTest, UngetAndReadBack) {
2424
constexpr size_t CONTENT_SIZE = sizeof(CONTENT);
2525
ASSERT_EQ(CONTENT_SIZE,
2626
LIBC_NAMESPACE::fwrite(CONTENT, 1, CONTENT_SIZE, file));
27+
#ifndef LIBC_TARGET_ARCH_IS_GPU // Behavior varies between libc implementations.
2728
// Cannot unget to an un-readable file.
2829
ASSERT_EQ(EOF, LIBC_NAMESPACE::ungetc('1', file));
30+
#endif
2931
ASSERT_EQ(0, LIBC_NAMESPACE::fclose(file));
3032

3133
file = LIBC_NAMESPACE::fopen(FILENAME, "r+");
3234
ASSERT_FALSE(file == nullptr);
35+
// Calling with an EOF should always return EOF without doing anything.
36+
ASSERT_EQ(EOF, LIBC_NAMESPACE::ungetc(EOF, file));
3337
char c;
3438
ASSERT_EQ(LIBC_NAMESPACE::fread(&c, 1, 1, file), size_t(1));
3539
ASSERT_EQ(c, CONTENT[0]);
@@ -43,8 +47,10 @@ TEST(LlvmLibcUngetcTest, UngetAndReadBack) {
4347
// ungetc should not fail after a seek operation.
4448
int unget_char = 'z';
4549
ASSERT_EQ(unget_char, LIBC_NAMESPACE::ungetc(unget_char, file));
50+
#ifndef LIBC_TARGET_ARCH_IS_GPU // Behavior varies between libc implementations.
4651
// Another unget should fail.
4752
ASSERT_EQ(EOF, LIBC_NAMESPACE::ungetc(unget_char, file));
53+
#endif
4854
// ungetting a char at the beginning of the file will allow us to fetch
4955
// one additional character.
5056
char new_data[CONTENT_SIZE + 1];
@@ -53,8 +59,10 @@ TEST(LlvmLibcUngetcTest, UngetAndReadBack) {
5359
ASSERT_STREQ("zabcdef", new_data);
5460

5561
ASSERT_EQ(size_t(1), LIBC_NAMESPACE::fwrite("x", 1, 1, file));
62+
#ifndef LIBC_TARGET_ARCH_IS_GPU // Behavior varies between libc implementations.
5663
// unget should fail after a write operation.
5764
ASSERT_EQ(EOF, LIBC_NAMESPACE::ungetc('1', file));
65+
#endif
5866

5967
ASSERT_EQ(0, LIBC_NAMESPACE::fclose(file));
6068
}

libc/utils/gpu/server/rpc_server.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,13 @@ struct Server {
186186
});
187187
break;
188188
}
189+
case RPC_UNGETC: {
190+
port->recv_and_send([](rpc::Buffer *buffer) {
191+
buffer->data[0] = ungetc(static_cast<int>(buffer->data[0]),
192+
file::to_stream(buffer->data[1]));
193+
});
194+
break;
195+
}
189196
case RPC_NOOP: {
190197
port->recv([](rpc::Buffer *) {});
191198
break;

0 commit comments

Comments
 (0)