mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-28 04:36:07 +00:00
[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.
This commit is contained in:
parent
761c9dd927
commit
ddc30ff802
@ -104,6 +104,7 @@ set(TARGET_LIBC_ENTRYPOINTS
|
||||
libc.src.stdio.fgetc
|
||||
libc.src.stdio.getc
|
||||
libc.src.stdio.getchar
|
||||
libc.src.stdio.ungetc
|
||||
libc.src.stdio.stdin
|
||||
libc.src.stdio.stdout
|
||||
libc.src.stdio.stderr
|
||||
|
@ -134,6 +134,7 @@ ftell |check| |check|
|
||||
fflush |check| |check|
|
||||
fgetc |check| |check|
|
||||
fgets |check| |check|
|
||||
ungetc |check| |check|
|
||||
getc |check| |check|
|
||||
getchar |check| |check|
|
||||
puts |check| |check|
|
||||
|
@ -29,6 +29,7 @@ typedef enum {
|
||||
RPC_FSEEK,
|
||||
RPC_FTELL,
|
||||
RPC_FFLUSH,
|
||||
RPC_UNGETC,
|
||||
RPC_LAST = 0xFFFF,
|
||||
} rpc_opcode_t;
|
||||
|
||||
|
@ -54,18 +54,6 @@ add_entrypoint_object(
|
||||
libc.src.__support.File.platform_file
|
||||
)
|
||||
|
||||
add_entrypoint_object(
|
||||
ungetc
|
||||
SRCS
|
||||
ungetc.cpp
|
||||
HDRS
|
||||
ungetc.h
|
||||
DEPENDS
|
||||
libc.include.stdio
|
||||
libc.src.__support.File.file
|
||||
libc.src.__support.File.platform_file
|
||||
)
|
||||
|
||||
add_entrypoint_object(
|
||||
fopencookie
|
||||
SRCS
|
||||
@ -286,6 +274,7 @@ 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(ungetc)
|
||||
add_stdio_entrypoint_object(stdin)
|
||||
add_stdio_entrypoint_object(stdout)
|
||||
add_stdio_entrypoint_object(stderr)
|
||||
|
@ -342,6 +342,18 @@ add_entrypoint_object(
|
||||
libc.src.__support.File.platform_file
|
||||
)
|
||||
|
||||
add_entrypoint_object(
|
||||
ungetc
|
||||
SRCS
|
||||
ungetc.cpp
|
||||
HDRS
|
||||
../ungetc.h
|
||||
DEPENDS
|
||||
libc.include.stdio
|
||||
libc.src.__support.File.file
|
||||
libc.src.__support.File.platform_file
|
||||
)
|
||||
|
||||
add_entrypoint_object(
|
||||
stdin
|
||||
SRCS
|
||||
|
@ -251,6 +251,17 @@ add_entrypoint_object(
|
||||
.ferror
|
||||
)
|
||||
|
||||
add_entrypoint_object(
|
||||
ungetc
|
||||
SRCS
|
||||
ungetc.cpp
|
||||
HDRS
|
||||
../ungetc.h
|
||||
DEPENDS
|
||||
libc.include.stdio
|
||||
.gpu_file
|
||||
)
|
||||
|
||||
add_entrypoint_object(
|
||||
stdin
|
||||
SRCS
|
||||
|
29
libc/src/stdio/gpu/ungetc.cpp
Normal file
29
libc/src/stdio/gpu/ungetc.cpp
Normal file
@ -0,0 +1,29 @@
|
||||
//===-- Implementation of ungetc ------------------------------------------===//
|
||||
//
|
||||
// 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/ungetc.h"
|
||||
#include "file.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
namespace LIBC_NAMESPACE {
|
||||
|
||||
LLVM_LIBC_FUNCTION(int, ungetc, (int c, ::FILE *stream)) {
|
||||
int ret;
|
||||
rpc::Client::Port port = rpc::client.open<RPC_UNGETC>();
|
||||
port.send_and_recv(
|
||||
[=](rpc::Buffer *buffer) {
|
||||
buffer->data[0] = c;
|
||||
buffer->data[1] = file::from_stream(stream);
|
||||
},
|
||||
[&](rpc::Buffer *buffer) { ret = static_cast<int>(buffer->data[0]); });
|
||||
port.close();
|
||||
return ret;
|
||||
}
|
||||
|
||||
} // namespace LIBC_NAMESPACE
|
@ -24,12 +24,16 @@ TEST(LlvmLibcUngetcTest, UngetAndReadBack) {
|
||||
constexpr size_t CONTENT_SIZE = sizeof(CONTENT);
|
||||
ASSERT_EQ(CONTENT_SIZE,
|
||||
LIBC_NAMESPACE::fwrite(CONTENT, 1, CONTENT_SIZE, file));
|
||||
#ifndef LIBC_TARGET_ARCH_IS_GPU // Behavior varies between libc implementations.
|
||||
// Cannot unget to an un-readable file.
|
||||
ASSERT_EQ(EOF, LIBC_NAMESPACE::ungetc('1', file));
|
||||
#endif
|
||||
ASSERT_EQ(0, LIBC_NAMESPACE::fclose(file));
|
||||
|
||||
file = LIBC_NAMESPACE::fopen(FILENAME, "r+");
|
||||
ASSERT_FALSE(file == nullptr);
|
||||
// Calling with an EOF should always return EOF without doing anything.
|
||||
ASSERT_EQ(EOF, LIBC_NAMESPACE::ungetc(EOF, file));
|
||||
char c;
|
||||
ASSERT_EQ(LIBC_NAMESPACE::fread(&c, 1, 1, file), size_t(1));
|
||||
ASSERT_EQ(c, CONTENT[0]);
|
||||
@ -43,8 +47,10 @@ TEST(LlvmLibcUngetcTest, UngetAndReadBack) {
|
||||
// ungetc should not fail after a seek operation.
|
||||
int unget_char = 'z';
|
||||
ASSERT_EQ(unget_char, LIBC_NAMESPACE::ungetc(unget_char, file));
|
||||
#ifndef LIBC_TARGET_ARCH_IS_GPU // Behavior varies between libc implementations.
|
||||
// Another unget should fail.
|
||||
ASSERT_EQ(EOF, LIBC_NAMESPACE::ungetc(unget_char, file));
|
||||
#endif
|
||||
// ungetting a char at the beginning of the file will allow us to fetch
|
||||
// one additional character.
|
||||
char new_data[CONTENT_SIZE + 1];
|
||||
@ -53,8 +59,10 @@ TEST(LlvmLibcUngetcTest, UngetAndReadBack) {
|
||||
ASSERT_STREQ("zabcdef", new_data);
|
||||
|
||||
ASSERT_EQ(size_t(1), LIBC_NAMESPACE::fwrite("x", 1, 1, file));
|
||||
#ifndef LIBC_TARGET_ARCH_IS_GPU // Behavior varies between libc implementations.
|
||||
// unget should fail after a write operation.
|
||||
ASSERT_EQ(EOF, LIBC_NAMESPACE::ungetc('1', file));
|
||||
#endif
|
||||
|
||||
ASSERT_EQ(0, LIBC_NAMESPACE::fclose(file));
|
||||
}
|
||||
|
@ -186,6 +186,13 @@ private:
|
||||
});
|
||||
break;
|
||||
}
|
||||
case RPC_UNGETC: {
|
||||
port->recv_and_send([](rpc::Buffer *buffer) {
|
||||
buffer->data[0] = ungetc(static_cast<int>(buffer->data[0]),
|
||||
file::to_stream(buffer->data[1]));
|
||||
});
|
||||
break;
|
||||
}
|
||||
case RPC_NOOP: {
|
||||
port->recv([](rpc::Buffer *) {});
|
||||
break;
|
||||
|
Loading…
x
Reference in New Issue
Block a user