[libc-commits] [libc] [libc] Template the writing mode for the writer class (PR #111559)
Joseph Huber via libc-commits
libc-commits at lists.llvm.org
Tue Oct 8 10:06:54 PDT 2024
https://github.com/jhuber6 created https://github.com/llvm/llvm-project/pull/111559
Summary:
Currently we dispatch the writing mode off of a runtime enum passed in
by the constructor. This causes very unfortunate codegen for the GPU
targets where we get worst-case codegen because of the unused function
pointer for `sprintf`. Instead, this patch moves all of this to a
template so it can be masked out. This results in no dynamic stack and
uses 60 VGPRs instead of 117. It also compiles about 5x as fast.
>From c7394d2504f84de0195261d03b43c21c1197980e Mon Sep 17 00:00:00 2001
From: Joseph Huber <huberjn at outlook.com>
Date: Tue, 8 Oct 2024 12:04:13 -0500
Subject: [PATCH] [libc] Template the writing mode for the writer class
Summary:
Currently we dispatch the writing mode off of a runtime enum passed in
by the constructor. This causes very unfortunate codegen for the GPU
targets where we get worst-case codegen because of the unused function
pointer for `sprintf`. Instead, this patch moves all of this to a
template so it can be masked out. This results in no dynamic stack and
uses 60 VGPRs instead of 117. It also compiles about 5x as fast.
---
libc/src/stdio/printf_core/CMakeLists.txt | 12 +-
libc/src/stdio/printf_core/char_converter.h | 4 +-
libc/src/stdio/printf_core/converter.cpp | 105 -----------------
libc/src/stdio/printf_core/converter.h | 85 +++++++++++++-
libc/src/stdio/printf_core/fixed_converter.h | 4 +-
.../stdio/printf_core/float_dec_converter.h | 60 ++++++----
.../stdio/printf_core/float_hex_converter.h | 3 +-
.../printf_core/float_inf_nan_converter.h | 4 +-
libc/src/stdio/printf_core/int_converter.h | 4 +-
libc/src/stdio/printf_core/printf_main.cpp | 43 -------
libc/src/stdio/printf_core/printf_main.h | 24 +++-
libc/src/stdio/printf_core/ptr_converter.h | 4 +-
.../stdio/printf_core/strerror_converter.h | 4 +-
libc/src/stdio/printf_core/string_converter.h | 4 +-
.../stdio/printf_core/vasprintf_internal.h | 15 +--
.../src/stdio/printf_core/vfprintf_internal.h | 6 +-
.../stdio/printf_core/write_int_converter.h | 3 +-
libc/src/stdio/printf_core/writer.cpp | 46 --------
libc/src/stdio/printf_core/writer.h | 107 +++++++++++-------
libc/src/stdio/snprintf.cpp | 5 +-
libc/src/stdio/sprintf.cpp | 5 +-
libc/src/stdio/vsnprintf.cpp | 5 +-
libc/src/stdio/vsprintf.cpp | 5 +-
libc/src/stdlib/str_from_util.h | 4 +-
libc/src/stdlib/strfromd.cpp | 5 +-
libc/src/stdlib/strfromf.cpp | 5 +-
libc/src/stdlib/strfroml.cpp | 5 +-
.../src/stdio/printf_core/converter_test.cpp | 12 +-
.../src/stdio/printf_core/writer_test.cpp | 80 +++++++------
libc/utils/gpu/server/CMakeLists.txt | 6 +-
libc/utils/gpu/server/rpc_server.cpp | 13 ++-
31 files changed, 335 insertions(+), 352 deletions(-)
delete mode 100644 libc/src/stdio/printf_core/converter.cpp
delete mode 100644 libc/src/stdio/printf_core/printf_main.cpp
delete mode 100644 libc/src/stdio/printf_core/writer.cpp
diff --git a/libc/src/stdio/printf_core/CMakeLists.txt b/libc/src/stdio/printf_core/CMakeLists.txt
index 8172fda1e866ed..4c9a9f5ceddb2f 100644
--- a/libc/src/stdio/printf_core/CMakeLists.txt
+++ b/libc/src/stdio/printf_core/CMakeLists.txt
@@ -59,10 +59,8 @@ add_header_library(
libc.src.__support.common
)
-add_object_library(
+add_header_library(
writer
- SRCS
- writer.cpp
HDRS
writer.h
DEPENDS
@@ -73,10 +71,8 @@ add_object_library(
libc.src.string.memory_utils.inline_memset
)
-add_object_library(
+add_header_library(
converter
- SRCS
- converter.cpp
HDRS
converter.h
converter_atlas.h
@@ -110,10 +106,8 @@ add_object_library(
libc.src.__support.StringUtil.error_to_string
)
-add_object_library(
+add_header_library(
printf_main
- SRCS
- printf_main.cpp
HDRS
printf_main.h
DEPENDS
diff --git a/libc/src/stdio/printf_core/char_converter.h b/libc/src/stdio/printf_core/char_converter.h
index 2596cba813c2e9..fd2eb2553887a8 100644
--- a/libc/src/stdio/printf_core/char_converter.h
+++ b/libc/src/stdio/printf_core/char_converter.h
@@ -17,7 +17,9 @@
namespace LIBC_NAMESPACE_DECL {
namespace printf_core {
-LIBC_INLINE int convert_char(Writer *writer, const FormatSection &to_conv) {
+template <WriteMode write_mode>
+LIBC_INLINE int convert_char(Writer<write_mode> *writer,
+ const FormatSection &to_conv) {
char c = static_cast<char>(to_conv.conv_val_raw);
constexpr int STRING_LEN = 1;
diff --git a/libc/src/stdio/printf_core/converter.cpp b/libc/src/stdio/printf_core/converter.cpp
deleted file mode 100644
index b1c66451f53f0f..00000000000000
--- a/libc/src/stdio/printf_core/converter.cpp
+++ /dev/null
@@ -1,105 +0,0 @@
-//===-- Format specifier converter implmentation for printf -----*- C++ -*-===//
-//
-// 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/printf_core/converter.h"
-
-#include "src/__support/macros/config.h"
-#include "src/stdio/printf_core/core_structs.h"
-#include "src/stdio/printf_core/printf_config.h"
-#include "src/stdio/printf_core/strerror_converter.h"
-#include "src/stdio/printf_core/writer.h"
-
-// This option allows for replacing all of the conversion functions with custom
-// replacements. This allows conversions to be replaced at compile time.
-#ifndef LIBC_COPT_PRINTF_CONV_ATLAS
-#include "src/stdio/printf_core/converter_atlas.h"
-#else
-#include LIBC_COPT_PRINTF_CONV_ATLAS
-#endif
-
-#include <stddef.h>
-
-namespace LIBC_NAMESPACE_DECL {
-namespace printf_core {
-
-int convert(Writer *writer, const FormatSection &to_conv) {
- if (!to_conv.has_conv)
- return writer->write(to_conv.raw_string);
-
-#if !defined(LIBC_COPT_PRINTF_DISABLE_FLOAT) && \
- defined(LIBC_COPT_PRINTF_HEX_LONG_DOUBLE)
- if (to_conv.length_modifier == LengthModifier::L) {
- switch (to_conv.conv_name) {
- case 'f':
- case 'F':
- case 'e':
- case 'E':
- case 'g':
- case 'G':
- return convert_float_hex_exp(writer, to_conv);
- default:
- break;
- }
- }
-#endif // LIBC_COPT_PRINTF_DISABLE_FLOAT
-
- switch (to_conv.conv_name) {
- case '%':
- return writer->write("%");
- case 'c':
- return convert_char(writer, to_conv);
- case 's':
- return convert_string(writer, to_conv);
- case 'd':
- case 'i':
- case 'u':
- case 'o':
- case 'x':
- case 'X':
- case 'b':
- case 'B':
- return convert_int(writer, to_conv);
-#ifndef LIBC_COPT_PRINTF_DISABLE_FLOAT
- case 'f':
- case 'F':
- return convert_float_decimal(writer, to_conv);
- case 'e':
- case 'E':
- return convert_float_dec_exp(writer, to_conv);
- case 'a':
- case 'A':
- return convert_float_hex_exp(writer, to_conv);
- case 'g':
- case 'G':
- return convert_float_dec_auto(writer, to_conv);
-#endif // LIBC_COPT_PRINTF_DISABLE_FLOAT
-#ifdef LIBC_INTERNAL_PRINTF_HAS_FIXED_POINT
- case 'r':
- case 'R':
- case 'k':
- case 'K':
- return convert_fixed(writer, to_conv);
-#endif // LIBC_INTERNAL_PRINTF_HAS_FIXED_POINT
-#ifndef LIBC_COPT_PRINTF_DISABLE_STRERROR
- case 'm':
- return convert_strerror(writer, to_conv);
-#endif // LIBC_COPT_PRINTF_DISABLE_STRERROR
-#ifndef LIBC_COPT_PRINTF_DISABLE_WRITE_INT
- case 'n':
- return convert_write_int(writer, to_conv);
-#endif // LIBC_COPT_PRINTF_DISABLE_WRITE_INT
- case 'p':
- return convert_pointer(writer, to_conv);
- default:
- return writer->write(to_conv.raw_string);
- }
- return -1;
-}
-
-} // namespace printf_core
-} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdio/printf_core/converter.h b/libc/src/stdio/printf_core/converter.h
index 2b3f06d0aa7a36..f26ed727f05f40 100644
--- a/libc/src/stdio/printf_core/converter.h
+++ b/libc/src/stdio/printf_core/converter.h
@@ -11,8 +11,18 @@
#include "src/__support/macros/config.h"
#include "src/stdio/printf_core/core_structs.h"
+#include "src/stdio/printf_core/printf_config.h"
+#include "src/stdio/printf_core/strerror_converter.h"
#include "src/stdio/printf_core/writer.h"
+// This option allows for replacing all of the conversion functions with custom
+// replacements. This allows conversions to be replaced at compile time.
+#ifndef LIBC_COPT_PRINTF_CONV_ATLAS
+#include "src/stdio/printf_core/converter_atlas.h"
+#else
+#include LIBC_COPT_PRINTF_CONV_ATLAS
+#endif
+
#include <stddef.h>
namespace LIBC_NAMESPACE_DECL {
@@ -21,7 +31,80 @@ namespace printf_core {
// convert will call a conversion function to convert the FormatSection into
// its string representation, and then that will write the result to the
// writer.
-int convert(Writer *writer, const FormatSection &to_conv);
+template <WriteMode write_mode>
+int convert(Writer<write_mode> *writer, const FormatSection &to_conv) {
+ if (!to_conv.has_conv)
+ return writer->write(to_conv.raw_string);
+
+#if !defined(LIBC_COPT_PRINTF_DISABLE_FLOAT) && \
+ defined(LIBC_COPT_PRINTF_HEX_LONG_DOUBLE)
+ if (to_conv.length_modifier == LengthModifier::L) {
+ switch (to_conv.conv_name) {
+ case 'f':
+ case 'F':
+ case 'e':
+ case 'E':
+ case 'g':
+ case 'G':
+ return convert_float_hex_exp(writer, to_conv);
+ default:
+ break;
+ }
+ }
+#endif // LIBC_COPT_PRINTF_DISABLE_FLOAT
+
+ switch (to_conv.conv_name) {
+ case '%':
+ return writer->write("%");
+ case 'c':
+ return convert_char(writer, to_conv);
+ case 's':
+ return convert_string(writer, to_conv);
+ case 'd':
+ case 'i':
+ case 'u':
+ case 'o':
+ case 'x':
+ case 'X':
+ case 'b':
+ case 'B':
+ return convert_int(writer, to_conv);
+#ifndef LIBC_COPT_PRINTF_DISABLE_FLOAT
+ case 'f':
+ case 'F':
+ return convert_float_decimal(writer, to_conv);
+ case 'e':
+ case 'E':
+ return convert_float_dec_exp(writer, to_conv);
+ case 'a':
+ case 'A':
+ return convert_float_hex_exp(writer, to_conv);
+ case 'g':
+ case 'G':
+ return convert_float_dec_auto(writer, to_conv);
+#endif // LIBC_COPT_PRINTF_DISABLE_FLOAT
+#ifdef LIBC_INTERNAL_PRINTF_HAS_FIXED_POINT
+ case 'r':
+ case 'R':
+ case 'k':
+ case 'K':
+ return convert_fixed(writer, to_conv);
+#endif // LIBC_INTERNAL_PRINTF_HAS_FIXED_POINT
+#ifndef LIBC_COPT_PRINTF_DISABLE_STRERROR
+ case 'm':
+ return convert_strerror(writer, to_conv);
+#endif // LIBC_COPT_PRINTF_DISABLE_STRERROR
+#ifndef LIBC_COPT_PRINTF_DISABLE_WRITE_INT
+ case 'n':
+ return convert_write_int(writer, to_conv);
+#endif // LIBC_COPT_PRINTF_DISABLE_WRITE_INT
+ case 'p':
+ return convert_pointer(writer, to_conv);
+ default:
+ return writer->write(to_conv.raw_string);
+ }
+ return -1;
+}
} // namespace printf_core
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdio/printf_core/fixed_converter.h b/libc/src/stdio/printf_core/fixed_converter.h
index c8812d77b62e34..6013c36b4cf3e9 100644
--- a/libc/src/stdio/printf_core/fixed_converter.h
+++ b/libc/src/stdio/printf_core/fixed_converter.h
@@ -62,7 +62,9 @@ LIBC_INLINE constexpr uint32_t const_ten_exp(uint32_t exponent) {
} \
} while (false)
-LIBC_INLINE int convert_fixed(Writer *writer, const FormatSection &to_conv) {
+template <WriteMode write_mode>
+LIBC_INLINE int convert_fixed(Writer<write_mode> *writer,
+ const FormatSection &to_conv) {
// Long accum should be the largest type, so we can store all the smaller
// numbers in things sized for it.
using LARep = fixed_point::FXRep<unsigned long accum>;
diff --git a/libc/src/stdio/printf_core/float_dec_converter.h b/libc/src/stdio/printf_core/float_dec_converter.h
index e39ba6ecea8d48..fd729f67d4dda5 100644
--- a/libc/src/stdio/printf_core/float_dec_converter.h
+++ b/libc/src/stdio/printf_core/float_dec_converter.h
@@ -92,7 +92,7 @@ zero_after_digits(int32_t base_2_exp, int32_t digits_after_point, T mantissa,
return has_trailing_zeros;
}
-class PaddingWriter {
+template <WriteMode write_mode> class PaddingWriter {
bool left_justified = false;
bool leading_zeroes = false;
char sign_char = 0;
@@ -106,7 +106,8 @@ class PaddingWriter {
sign_char(init_sign_char),
min_width(to_conv.min_width > 0 ? to_conv.min_width : 0) {}
- LIBC_INLINE int write_left_padding(Writer *writer, size_t total_digits) {
+ LIBC_INLINE int write_left_padding(Writer<write_mode> *writer,
+ size_t total_digits) {
// The pattern is (spaces) (sign) (zeroes), but only one of spaces and
// zeroes can be written, and only if the padding amount is positive.
int padding_amount =
@@ -129,7 +130,8 @@ class PaddingWriter {
return 0;
}
- LIBC_INLINE int write_right_padding(Writer *writer, size_t total_digits) {
+ LIBC_INLINE int write_right_padding(Writer<write_mode> *writer,
+ size_t total_digits) {
// If and only if the conversion is left justified, there may be trailing
// spaces.
int padding_amount =
@@ -154,7 +156,7 @@ class PaddingWriter {
This FloatWriter class does the buffering and counting, and writes to the
output when necessary.
*/
-class FloatWriter {
+template <WriteMode write_mode> class FloatWriter {
char block_buffer[BLOCK_SIZE]; // The buffer that holds a block.
size_t buffered_digits = 0; // The number of digits held in the buffer.
bool has_written = false; // True once any digits have been output.
@@ -163,8 +165,9 @@ class FloatWriter {
size_t digits_before_decimal = 0; // The # of digits to write before the '.'
size_t total_digits_written = 0; // The # of digits that have been output.
bool has_decimal_point; // True if the number has a decimal point.
- Writer *writer; // Writes to the final output.
- PaddingWriter padding_writer; // Handles prefixes/padding, uses total_digits.
+ Writer<write_mode> *writer; // Writes to the final output.
+ PaddingWriter<write_mode>
+ padding_writer; // Handles prefixes/padding, uses total_digits.
LIBC_INLINE int flush_buffer(bool round_up_max_blocks = false) {
const char MAX_BLOCK_DIGIT = (round_up_max_blocks ? '0' : '9');
@@ -244,8 +247,9 @@ class FloatWriter {
static_assert(fputil::FPBits<long double>::EXP_LEN < (sizeof(int) * 8));
public:
- LIBC_INLINE FloatWriter(Writer *init_writer, bool init_has_decimal_point,
- const PaddingWriter &init_padding_writer)
+ LIBC_INLINE FloatWriter(Writer<write_mode> *init_writer,
+ bool init_has_decimal_point,
+ const PaddingWriter<write_mode> &init_padding_writer)
: has_decimal_point(init_has_decimal_point), writer(init_writer),
padding_writer(init_padding_writer) {}
@@ -465,12 +469,24 @@ class FloatWriter {
}
};
+// Class-template auto deduction helpers.
+FloatWriter(Writer<WriteMode::FILL_BUFF_AND_DROP_OVERFLOW>, bool,
+ const PaddingWriter<WriteMode::FILL_BUFF_AND_DROP_OVERFLOW>)
+ -> FloatWriter<WriteMode::FILL_BUFF_AND_DROP_OVERFLOW>;
+FloatWriter(Writer<WriteMode::RESIZE_AND_FILL_BUFF>, bool,
+ const PaddingWriter<WriteMode::RESIZE_AND_FILL_BUFF>)
+ -> FloatWriter<WriteMode::RESIZE_AND_FILL_BUFF>;
+FloatWriter(Writer<WriteMode::FLUSH_TO_STREAM>, bool,
+ const PaddingWriter<WriteMode::FLUSH_TO_STREAM>)
+ -> FloatWriter<WriteMode::FLUSH_TO_STREAM>;
+
// This implementation is based on the Ryu Printf algorithm by Ulf Adams:
// Ulf Adams. 2019. Ryƫ revisited: printf floating point conversion.
// Proc. ACM Program. Lang. 3, OOPSLA, Article 169 (October 2019), 23 pages.
// https://doi.org/10.1145/3360595
-template <typename T, cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0>
-LIBC_INLINE int convert_float_decimal_typed(Writer *writer,
+template <typename T, WriteMode write_mode,
+ cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0>
+LIBC_INLINE int convert_float_decimal_typed(Writer<write_mode> *writer,
const FormatSection &to_conv,
fputil::FPBits<T> float_bits) {
// signed because later we use -FRACTION_LEN
@@ -497,7 +513,7 @@ LIBC_INLINE int convert_float_decimal_typed(Writer *writer,
// ignored.
bool nonzero = false;
- PaddingWriter padding_writer(to_conv, sign_char);
+ PaddingWriter<write_mode> padding_writer(to_conv, sign_char);
FloatWriter float_writer(writer, has_decimal_point, padding_writer);
FloatToString<T> float_converter(float_bits.get_val());
@@ -578,8 +594,9 @@ LIBC_INLINE int convert_float_decimal_typed(Writer *writer,
return WRITE_OK;
}
-template <typename T, cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0>
-LIBC_INLINE int convert_float_dec_exp_typed(Writer *writer,
+template <typename T, WriteMode write_mode,
+ cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0>
+LIBC_INLINE int convert_float_dec_exp_typed(Writer<write_mode> *writer,
const FormatSection &to_conv,
fputil::FPBits<T> float_bits) {
// signed because later we use -FRACTION_LEN
@@ -604,7 +621,7 @@ LIBC_INLINE int convert_float_dec_exp_typed(Writer *writer,
bool has_decimal_point =
(precision > 0) || ((to_conv.flags & FormatFlags::ALTERNATE_FORM) != 0);
- PaddingWriter padding_writer(to_conv, sign_char);
+ PaddingWriter<write_mode> padding_writer(to_conv, sign_char);
FloatWriter float_writer(writer, has_decimal_point, padding_writer);
FloatToString<T> float_converter(float_bits.get_val());
@@ -740,8 +757,9 @@ LIBC_INLINE int convert_float_dec_exp_typed(Writer *writer,
return WRITE_OK;
}
-template <typename T, cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0>
-LIBC_INLINE int convert_float_dec_auto_typed(Writer *writer,
+template <typename T, WriteMode write_mode,
+ cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0>
+LIBC_INLINE int convert_float_dec_auto_typed(Writer<write_mode> *writer,
const FormatSection &to_conv,
fputil::FPBits<T> float_bits) {
// signed because later we use -FRACTION_LEN
@@ -1107,7 +1125,9 @@ LIBC_INLINE int convert_float_dec_auto_typed(Writer *writer,
}
// TODO: unify the float converters to remove the duplicated checks for inf/nan.
-LIBC_INLINE int convert_float_decimal(Writer *writer,
+
+template <WriteMode write_mode>
+LIBC_INLINE int convert_float_decimal(Writer<write_mode> *writer,
const FormatSection &to_conv) {
if (to_conv.length_modifier == LengthModifier::L) {
fputil::FPBits<long double>::StorageType float_raw = to_conv.conv_val_raw;
@@ -1128,7 +1148,8 @@ LIBC_INLINE int convert_float_decimal(Writer *writer,
return convert_inf_nan(writer, to_conv);
}
-LIBC_INLINE int convert_float_dec_exp(Writer *writer,
+template <WriteMode write_mode>
+LIBC_INLINE int convert_float_dec_exp(Writer<write_mode> *writer,
const FormatSection &to_conv) {
if (to_conv.length_modifier == LengthModifier::L) {
fputil::FPBits<long double>::StorageType float_raw = to_conv.conv_val_raw;
@@ -1149,7 +1170,8 @@ LIBC_INLINE int convert_float_dec_exp(Writer *writer,
return convert_inf_nan(writer, to_conv);
}
-LIBC_INLINE int convert_float_dec_auto(Writer *writer,
+template <WriteMode write_mode>
+LIBC_INLINE int convert_float_dec_auto(Writer<write_mode> *writer,
const FormatSection &to_conv) {
if (to_conv.length_modifier == LengthModifier::L) {
fputil::FPBits<long double>::StorageType float_raw = to_conv.conv_val_raw;
diff --git a/libc/src/stdio/printf_core/float_hex_converter.h b/libc/src/stdio/printf_core/float_hex_converter.h
index 0b3ff3dd1cbfdc..3d41f8a45b0bb3 100644
--- a/libc/src/stdio/printf_core/float_hex_converter.h
+++ b/libc/src/stdio/printf_core/float_hex_converter.h
@@ -24,7 +24,8 @@
namespace LIBC_NAMESPACE_DECL {
namespace printf_core {
-LIBC_INLINE int convert_float_hex_exp(Writer *writer,
+template <WriteMode write_mode>
+LIBC_INLINE int convert_float_hex_exp(Writer<write_mode> *writer,
const FormatSection &to_conv) {
using LDBits = fputil::FPBits<long double>;
using StorageType = LDBits::StorageType;
diff --git a/libc/src/stdio/printf_core/float_inf_nan_converter.h b/libc/src/stdio/printf_core/float_inf_nan_converter.h
index a7da682b835bee..8988d6474bf409 100644
--- a/libc/src/stdio/printf_core/float_inf_nan_converter.h
+++ b/libc/src/stdio/printf_core/float_inf_nan_converter.h
@@ -23,7 +23,9 @@ namespace printf_core {
using StorageType = fputil::FPBits<long double>::StorageType;
-LIBC_INLINE int convert_inf_nan(Writer *writer, const FormatSection &to_conv) {
+template <WriteMode write_mode>
+LIBC_INLINE int convert_inf_nan(Writer<write_mode> *writer,
+ const FormatSection &to_conv) {
// All of the letters will be defined relative to variable a, which will be
// the appropriate case based on the case of the conversion.
const char a = (to_conv.conv_name & 32) | 'A';
diff --git a/libc/src/stdio/printf_core/int_converter.h b/libc/src/stdio/printf_core/int_converter.h
index f345e86b97a691..22f4dd627a104b 100644
--- a/libc/src/stdio/printf_core/int_converter.h
+++ b/libc/src/stdio/printf_core/int_converter.h
@@ -65,7 +65,9 @@ num_to_strview(uintmax_t num, cpp::span<char> bufref, char conv_name) {
} // namespace details
-LIBC_INLINE int convert_int(Writer *writer, const FormatSection &to_conv) {
+template <WriteMode write_mode>
+LIBC_INLINE int convert_int(Writer<write_mode> *writer,
+ const FormatSection &to_conv) {
static constexpr size_t BITS_IN_BYTE = 8;
static constexpr size_t BITS_IN_NUM = sizeof(uintmax_t) * BITS_IN_BYTE;
diff --git a/libc/src/stdio/printf_core/printf_main.cpp b/libc/src/stdio/printf_core/printf_main.cpp
deleted file mode 100644
index bd4a5a168bd23e..00000000000000
--- a/libc/src/stdio/printf_core/printf_main.cpp
+++ /dev/null
@@ -1,43 +0,0 @@
-//===-- Starting point for printf -------------------------------*- C++ -*-===//
-//
-// 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/printf_core/printf_main.h"
-
-#include "src/__support/arg_list.h"
-#include "src/__support/macros/config.h"
-#include "src/stdio/printf_core/converter.h"
-#include "src/stdio/printf_core/core_structs.h"
-#include "src/stdio/printf_core/parser.h"
-#include "src/stdio/printf_core/writer.h"
-
-#include <stddef.h>
-
-namespace LIBC_NAMESPACE_DECL {
-namespace printf_core {
-
-int printf_main(Writer *writer, const char *__restrict str,
- internal::ArgList &args) {
- Parser<internal::ArgList> parser(str, args);
- int result = 0;
- for (FormatSection cur_section = parser.get_next_section();
- !cur_section.raw_string.empty();
- cur_section = parser.get_next_section()) {
- if (cur_section.has_conv)
- result = convert(writer, cur_section);
- else
- result = writer->write(cur_section.raw_string);
-
- if (result < 0)
- return result;
- }
-
- return writer->get_chars_written();
-}
-
-} // namespace printf_core
-} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdio/printf_core/printf_main.h b/libc/src/stdio/printf_core/printf_main.h
index 3e73bf36e0e309..57f29858d5298d 100644
--- a/libc/src/stdio/printf_core/printf_main.h
+++ b/libc/src/stdio/printf_core/printf_main.h
@@ -11,6 +11,9 @@
#include "src/__support/arg_list.h"
#include "src/__support/macros/config.h"
+#include "src/stdio/printf_core/converter.h"
+#include "src/stdio/printf_core/core_structs.h"
+#include "src/stdio/printf_core/parser.h"
#include "src/stdio/printf_core/writer.h"
#include <stddef.h>
@@ -18,8 +21,25 @@
namespace LIBC_NAMESPACE_DECL {
namespace printf_core {
-int printf_main(Writer *writer, const char *__restrict str,
- internal::ArgList &args);
+template <WriteMode write_mode>
+int printf_main(Writer<write_mode> *writer, const char *__restrict str,
+ internal::ArgList &args) {
+ Parser<internal::ArgList> parser(str, args);
+ int result = 0;
+ for (FormatSection cur_section = parser.get_next_section();
+ !cur_section.raw_string.empty();
+ cur_section = parser.get_next_section()) {
+ if (cur_section.has_conv)
+ result = convert(writer, cur_section);
+ else
+ result = writer->write(cur_section.raw_string);
+
+ if (result < 0)
+ return result;
+ }
+
+ return writer->get_chars_written();
+}
} // namespace printf_core
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdio/printf_core/ptr_converter.h b/libc/src/stdio/printf_core/ptr_converter.h
index bf84718dfe6a86..c2a74e3043e6f6 100644
--- a/libc/src/stdio/printf_core/ptr_converter.h
+++ b/libc/src/stdio/printf_core/ptr_converter.h
@@ -18,7 +18,9 @@
namespace LIBC_NAMESPACE_DECL {
namespace printf_core {
-LIBC_INLINE int convert_pointer(Writer *writer, const FormatSection &to_conv) {
+template <WriteMode write_mode>
+LIBC_INLINE int convert_pointer(Writer<write_mode> *writer,
+ const FormatSection &to_conv) {
FormatSection new_conv = to_conv;
if (to_conv.conv_val_ptr == nullptr) {
diff --git a/libc/src/stdio/printf_core/strerror_converter.h b/libc/src/stdio/printf_core/strerror_converter.h
index 2902fd37c31ae3..2cd6df0c01d457 100644
--- a/libc/src/stdio/printf_core/strerror_converter.h
+++ b/libc/src/stdio/printf_core/strerror_converter.h
@@ -19,7 +19,9 @@
namespace LIBC_NAMESPACE_DECL {
namespace printf_core {
-LIBC_INLINE int convert_strerror(Writer *writer, const FormatSection &to_conv) {
+template <WriteMode write_mode>
+LIBC_INLINE int convert_strerror(Writer<write_mode> *writer,
+ const FormatSection &to_conv) {
FormatSection new_conv = to_conv;
const int error_num = static_cast<int>(to_conv.conv_val_raw);
diff --git a/libc/src/stdio/printf_core/string_converter.h b/libc/src/stdio/printf_core/string_converter.h
index 1f36d511241076..74c9f598210f77 100644
--- a/libc/src/stdio/printf_core/string_converter.h
+++ b/libc/src/stdio/printf_core/string_converter.h
@@ -20,7 +20,9 @@
namespace LIBC_NAMESPACE_DECL {
namespace printf_core {
-LIBC_INLINE int convert_string(Writer *writer, const FormatSection &to_conv) {
+template <WriteMode write_mode>
+LIBC_INLINE int convert_string(Writer<write_mode> *writer,
+ const FormatSection &to_conv) {
size_t string_len = 0;
const char *str_ptr = reinterpret_cast<const char *>(to_conv.conv_val_ptr);
diff --git a/libc/src/stdio/printf_core/vasprintf_internal.h b/libc/src/stdio/printf_core/vasprintf_internal.h
index 24ebc02a0b33f2..a3112e16aef0ad 100644
--- a/libc/src/stdio/printf_core/vasprintf_internal.h
+++ b/libc/src/stdio/printf_core/vasprintf_internal.h
@@ -13,12 +13,13 @@
#include "src/stdio/printf_core/writer.h"
#include <stdlib.h> // malloc, realloc, free
-namespace LIBC_NAMESPACE {
+namespace LIBC_NAMESPACE_DECL {
namespace printf_core {
LIBC_INLINE int resize_overflow_hook(cpp::string_view new_str, void *target) {
- printf_core::WriteBuffer *wb =
- reinterpret_cast<printf_core::WriteBuffer *>(target);
+ printf_core::WriteBuffer<WriteMode::RESIZE_AND_FILL_BUFF> *wb =
+ reinterpret_cast<
+ printf_core::WriteBuffer<WriteMode::RESIZE_AND_FILL_BUFF> *>(target);
size_t new_size = new_str.size() + wb->buff_cur;
const bool isBuffOnStack = (wb->buff == wb->init_buff);
char *new_buff = static_cast<char *>(
@@ -43,9 +44,9 @@ constexpr size_t DEFAULT_BUFFER_SIZE = 200;
LIBC_INLINE int vasprintf_internal(char **ret, const char *format,
internal::ArgList args) {
char init_buff_on_stack[DEFAULT_BUFFER_SIZE];
- printf_core::WriteBuffer wb(init_buff_on_stack, DEFAULT_BUFFER_SIZE,
- resize_overflow_hook);
- printf_core::Writer writer(&wb);
+ printf_core::WriteBuffer<WriteMode::RESIZE_AND_FILL_BUFF> wb(
+ init_buff_on_stack, DEFAULT_BUFFER_SIZE, resize_overflow_hook);
+ printf_core::Writer writer(wb);
auto ret_val = printf_core::printf_main(&writer, format, args);
if (ret_val < 0) {
@@ -64,4 +65,4 @@ LIBC_INLINE int vasprintf_internal(char **ret, const char *format,
return ret_val;
}
} // namespace printf_core
-} // namespace LIBC_NAMESPACE
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdio/printf_core/vfprintf_internal.h b/libc/src/stdio/printf_core/vfprintf_internal.h
index 3becfee71dd273..810b135776cffe 100644
--- a/libc/src/stdio/printf_core/vfprintf_internal.h
+++ b/libc/src/stdio/printf_core/vfprintf_internal.h
@@ -72,9 +72,9 @@ LIBC_INLINE int vfprintf_internal(::FILE *__restrict stream,
internal::ArgList &args) {
constexpr size_t BUFF_SIZE = 1024;
char buffer[BUFF_SIZE];
- printf_core::WriteBuffer wb(buffer, BUFF_SIZE, &file_write_hook,
- reinterpret_cast<void *>(stream));
- Writer writer(&wb);
+ printf_core::WriteBuffer<WriteMode::FLUSH_TO_STREAM> wb(
+ buffer, BUFF_SIZE, &file_write_hook, reinterpret_cast<void *>(stream));
+ Writer writer(wb);
internal::flockfile(stream);
int retval = printf_main(&writer, format, args);
int flushval = wb.overflow_write("");
diff --git a/libc/src/stdio/printf_core/write_int_converter.h b/libc/src/stdio/printf_core/write_int_converter.h
index a47cb41cb3287c..efcff278bd284c 100644
--- a/libc/src/stdio/printf_core/write_int_converter.h
+++ b/libc/src/stdio/printf_core/write_int_converter.h
@@ -19,7 +19,8 @@
namespace LIBC_NAMESPACE_DECL {
namespace printf_core {
-LIBC_INLINE int convert_write_int(Writer *writer,
+template <WriteMode write_mode>
+LIBC_INLINE int convert_write_int(Writer<write_mode> *writer,
const FormatSection &to_conv) {
#ifndef LIBC_COPT_PRINTF_NO_NULLPTR_CHECKS
diff --git a/libc/src/stdio/printf_core/writer.cpp b/libc/src/stdio/printf_core/writer.cpp
deleted file mode 100644
index d1cf85df1c8f89..00000000000000
--- a/libc/src/stdio/printf_core/writer.cpp
+++ /dev/null
@@ -1,46 +0,0 @@
-//===-- Writer definition for printf ----------------------------*- C++ -*-===//
-//
-// 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 "writer.h"
-#include "src/__support/CPP/string_view.h"
-#include "src/__support/macros/config.h"
-#include "src/stdio/printf_core/core_structs.h"
-#include "src/string/memory_utils/inline_memset.h"
-#include <stddef.h>
-
-namespace LIBC_NAMESPACE_DECL {
-namespace printf_core {
-
-int Writer::pad(char new_char, size_t length) {
- // First, fill as much of the buffer as possible with the padding char.
- size_t written = 0;
- const size_t buff_space = wb->buff_len - wb->buff_cur;
- // ASSERT: length > buff_space
- if (buff_space > 0) {
- inline_memset(wb->buff + wb->buff_cur, new_char, buff_space);
- wb->buff_cur += buff_space;
- written = buff_space;
- }
-
- // Next, overflow write the rest of length using the mini_buff.
- constexpr size_t MINI_BUFF_SIZE = 64;
- char mini_buff[MINI_BUFF_SIZE];
- inline_memset(mini_buff, new_char, MINI_BUFF_SIZE);
- cpp::string_view mb_string_view(mini_buff, MINI_BUFF_SIZE);
- while (written + MINI_BUFF_SIZE < length) {
- int result = wb->overflow_write(mb_string_view);
- if (result != WRITE_OK)
- return result;
- written += MINI_BUFF_SIZE;
- }
- cpp::string_view mb_substr = mb_string_view.substr(0, length - written);
- return wb->overflow_write(mb_substr);
-}
-
-} // namespace printf_core
-} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdio/printf_core/writer.h b/libc/src/stdio/printf_core/writer.h
index 5526a478ea620e..aef91304532576 100644
--- a/libc/src/stdio/printf_core/writer.h
+++ b/libc/src/stdio/printf_core/writer.h
@@ -21,12 +21,13 @@
namespace LIBC_NAMESPACE_DECL {
namespace printf_core {
-struct WriteBuffer {
- enum class WriteMode {
- FILL_BUFF_AND_DROP_OVERFLOW,
- FLUSH_TO_STREAM,
- RESIZE_AND_FILL_BUFF,
- };
+enum class WriteMode {
+ FILL_BUFF_AND_DROP_OVERFLOW,
+ FLUSH_TO_STREAM,
+ RESIZE_AND_FILL_BUFF,
+};
+
+template <WriteMode write_mode> struct WriteBuffer {
using StreamWriter = int (*)(cpp::string_view, void *);
char *buff;
const char *init_buff; // for checking when resize.
@@ -35,23 +36,21 @@ struct WriteBuffer {
// The stream writer will be called when the buffer is full. It will be passed
// string_views to write to the stream.
- StreamWriter stream_writer;
+ const StreamWriter stream_writer;
void *output_target;
- WriteMode write_mode;
- LIBC_INLINE WriteBuffer(char *Buff, size_t Buff_len, StreamWriter hook,
+ LIBC_INLINE WriteBuffer(char *buff, size_t buff_len, StreamWriter hook,
void *target)
- : buff(Buff), init_buff(Buff), buff_len(Buff_len), stream_writer(hook),
- output_target(target), write_mode(WriteMode::FLUSH_TO_STREAM) {}
+ : buff(buff), init_buff(buff), buff_len(buff_len), stream_writer(hook),
+ output_target(target) {}
- LIBC_INLINE WriteBuffer(char *Buff, size_t Buff_len)
- : buff(Buff), init_buff(Buff), buff_len(Buff_len), stream_writer(nullptr),
- output_target(nullptr),
- write_mode(WriteMode::FILL_BUFF_AND_DROP_OVERFLOW) {}
+ LIBC_INLINE WriteBuffer(char *buff, size_t buff_len)
+ : buff(buff), init_buff(buff), buff_len(buff_len), stream_writer(nullptr),
+ output_target(nullptr) {}
- LIBC_INLINE WriteBuffer(char *Buff, size_t Buff_len, StreamWriter hook)
- : buff(Buff), init_buff(Buff), buff_len(Buff_len), stream_writer(hook),
- output_target(this), write_mode(WriteMode::RESIZE_AND_FILL_BUFF) {}
+ LIBC_INLINE WriteBuffer(char *buff, size_t buff_len, StreamWriter hook)
+ : buff(buff), init_buff(buff), buff_len(buff_len), stream_writer(hook),
+ output_target(this) {}
LIBC_INLINE int flush_to_stream(cpp::string_view new_str) {
if (buff_cur > 0) {
@@ -92,40 +91,60 @@ struct WriteBuffer {
// this with an empty string will flush the buffer if relevant.
LIBC_INLINE int overflow_write(cpp::string_view new_str) {
- switch (write_mode) {
- case WriteMode::FILL_BUFF_AND_DROP_OVERFLOW:
+ if constexpr (write_mode == WriteMode::FILL_BUFF_AND_DROP_OVERFLOW)
return fill_remaining_to_buff(new_str);
- case WriteMode::FLUSH_TO_STREAM:
+ else if constexpr (write_mode == WriteMode::FLUSH_TO_STREAM)
return flush_to_stream(new_str);
- case WriteMode::RESIZE_AND_FILL_BUFF:
+ else if constexpr (write_mode == WriteMode::RESIZE_AND_FILL_BUFF)
return resize_and_write(new_str);
- }
__builtin_unreachable();
}
};
-class Writer final {
- WriteBuffer *wb;
+template <WriteMode write_mode> class Writer final {
+ WriteBuffer<write_mode> &wb;
int chars_written = 0;
- // This is a separate, non-inlined function so that the inlined part of the
- // write function is shorter.
- int pad(char new_char, size_t length);
+ LIBC_INLINE int pad(char new_char, size_t length) {
+ // First, fill as much of the buffer as possible with the padding char.
+ size_t written = 0;
+ const size_t buff_space = wb.buff_len - wb.buff_cur;
+ // ASSERT: length > buff_space
+ if (buff_space > 0) {
+ inline_memset(wb.buff + wb.buff_cur, new_char, buff_space);
+ wb.buff_cur += buff_space;
+ written = buff_space;
+ }
+
+ // Next, overflow write the rest of length using the mini_buff.
+ constexpr size_t MINI_BUFF_SIZE = 64;
+ char mini_buff[MINI_BUFF_SIZE];
+ inline_memset(mini_buff, new_char, MINI_BUFF_SIZE);
+ cpp::string_view mb_string_view(mini_buff, MINI_BUFF_SIZE);
+ while (written + MINI_BUFF_SIZE < length) {
+ int result = wb.overflow_write(mb_string_view);
+ if (result != WRITE_OK)
+ return result;
+ written += MINI_BUFF_SIZE;
+ }
+ cpp::string_view mb_substr = mb_string_view.substr(0, length - written);
+ return wb.overflow_write(mb_substr);
+ }
public:
- LIBC_INLINE Writer(WriteBuffer *WB) : wb(WB) {}
+ LIBC_INLINE Writer(WriteBuffer<write_mode> &wb) : wb(wb) {}
// Takes a string, copies it into the buffer if there is space, else passes it
// to the overflow mechanism to be handled separately.
LIBC_INLINE int write(cpp::string_view new_string) {
chars_written += static_cast<int>(new_string.size());
- if (LIBC_LIKELY(wb->buff_cur + new_string.size() <= wb->buff_len)) {
- inline_memcpy(wb->buff + wb->buff_cur, new_string.data(),
+ if (LIBC_LIKELY(wb.buff_cur + new_string.size() <= wb.buff_len)) {
+ inline_memcpy(wb.buff + wb.buff_cur, new_string.data(),
new_string.size());
- wb->buff_cur += new_string.size();
+ wb.buff_cur += new_string.size();
return WRITE_OK;
}
- return wb->overflow_write(new_string);
+ return wb.overflow_write(new_string);
}
// Takes a char and a length, memsets the next length characters of the buffer
@@ -134,9 +153,9 @@ class Writer final {
LIBC_INLINE int write(char new_char, size_t length) {
chars_written += static_cast<int>(length);
- if (LIBC_LIKELY(wb->buff_cur + length <= wb->buff_len)) {
- inline_memset(wb->buff + wb->buff_cur, new_char, length);
- wb->buff_cur += length;
+ if (LIBC_LIKELY(wb.buff_cur + length <= wb.buff_len)) {
+ inline_memset(wb.buff + wb.buff_cur, new_char, length);
+ wb.buff_cur += length;
return WRITE_OK;
}
return pad(new_char, length);
@@ -146,18 +165,26 @@ class Writer final {
// to the overflow mechanism to be handled separately.
LIBC_INLINE int write(char new_char) {
chars_written += 1;
- if (LIBC_LIKELY(wb->buff_cur + 1 <= wb->buff_len)) {
- wb->buff[wb->buff_cur] = new_char;
- wb->buff_cur += 1;
+ if (LIBC_LIKELY(wb.buff_cur + 1 <= wb.buff_len)) {
+ wb.buff[wb.buff_cur] = new_char;
+ wb.buff_cur += 1;
return WRITE_OK;
}
cpp::string_view char_string_view(&new_char, 1);
- return wb->overflow_write(char_string_view);
+ return wb.overflow_write(char_string_view);
}
LIBC_INLINE int get_chars_written() { return chars_written; }
};
+// Class-template auto deduction helpers.
+Writer(WriteBuffer<WriteMode::FILL_BUFF_AND_DROP_OVERFLOW>)
+ -> Writer<WriteMode::FILL_BUFF_AND_DROP_OVERFLOW>;
+Writer(WriteBuffer<WriteMode::RESIZE_AND_FILL_BUFF>)
+ -> Writer<WriteMode::RESIZE_AND_FILL_BUFF>;
+Writer(WriteBuffer<WriteMode::FLUSH_TO_STREAM>)
+ -> Writer<WriteMode::FLUSH_TO_STREAM>;
+
} // namespace printf_core
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdio/snprintf.cpp b/libc/src/stdio/snprintf.cpp
index 12ad3cd1f762b2..8ddb1cbba3d9cc 100644
--- a/libc/src/stdio/snprintf.cpp
+++ b/libc/src/stdio/snprintf.cpp
@@ -27,8 +27,9 @@ LLVM_LIBC_FUNCTION(int, snprintf,
// and pointer semantics, as well as handling
// destruction automatically.
va_end(vlist);
- printf_core::WriteBuffer wb(buffer, (buffsz > 0 ? buffsz - 1 : 0));
- printf_core::Writer writer(&wb);
+ printf_core::WriteBuffer<printf_core::WriteMode::FILL_BUFF_AND_DROP_OVERFLOW>
+ wb(buffer, (buffsz > 0 ? buffsz - 1 : 0));
+ printf_core::Writer writer(wb);
int ret_val = printf_core::printf_main(&writer, format, args);
if (buffsz > 0) // if the buffsz is 0 the buffer may be a null pointer.
diff --git a/libc/src/stdio/sprintf.cpp b/libc/src/stdio/sprintf.cpp
index 1f59e6bae4723c..13c472ada6250f 100644
--- a/libc/src/stdio/sprintf.cpp
+++ b/libc/src/stdio/sprintf.cpp
@@ -28,8 +28,9 @@ LLVM_LIBC_FUNCTION(int, sprintf,
// destruction automatically.
va_end(vlist);
- printf_core::WriteBuffer wb(buffer, cpp::numeric_limits<size_t>::max());
- printf_core::Writer writer(&wb);
+ printf_core::WriteBuffer<printf_core::WriteMode::RESIZE_AND_FILL_BUFF> wb(
+ buffer, cpp::numeric_limits<size_t>::max());
+ printf_core::Writer writer(wb);
int ret_val = printf_core::printf_main(&writer, format, args);
wb.buff[wb.buff_cur] = '\0';
diff --git a/libc/src/stdio/vsnprintf.cpp b/libc/src/stdio/vsnprintf.cpp
index a584c76833a2dd..12192e03577368 100644
--- a/libc/src/stdio/vsnprintf.cpp
+++ b/libc/src/stdio/vsnprintf.cpp
@@ -24,8 +24,9 @@ LLVM_LIBC_FUNCTION(int, vsnprintf,
internal::ArgList args(vlist); // This holder class allows for easier copying
// and pointer semantics, as well as handling
// destruction automatically.
- printf_core::WriteBuffer wb(buffer, (buffsz > 0 ? buffsz - 1 : 0));
- printf_core::Writer writer(&wb);
+ printf_core::WriteBuffer<printf_core::WriteMode::FILL_BUFF_AND_DROP_OVERFLOW>
+ wb(buffer, (buffsz > 0 ? buffsz - 1 : 0));
+ printf_core::Writer writer(wb);
int ret_val = printf_core::printf_main(&writer, format, args);
if (buffsz > 0) // if the buffsz is 0 the buffer may be a null pointer.
diff --git a/libc/src/stdio/vsprintf.cpp b/libc/src/stdio/vsprintf.cpp
index b3978a09c671ab..989a803a4e0bcf 100644
--- a/libc/src/stdio/vsprintf.cpp
+++ b/libc/src/stdio/vsprintf.cpp
@@ -25,8 +25,9 @@ LLVM_LIBC_FUNCTION(int, vsprintf,
// and pointer semantics, as well as handling
// destruction automatically.
- printf_core::WriteBuffer wb(buffer, cpp::numeric_limits<size_t>::max());
- printf_core::Writer writer(&wb);
+ printf_core::WriteBuffer<printf_core::WriteMode::FILL_BUFF_AND_DROP_OVERFLOW>
+ wb(buffer, cpp::numeric_limits<size_t>::max());
+ printf_core::Writer writer(wb);
int ret_val = printf_core::printf_main(&writer, format, args);
wb.buff[wb.buff_cur] = '\0';
diff --git a/libc/src/stdlib/str_from_util.h b/libc/src/stdlib/str_from_util.h
index 7f54bdf71a0182..61e6ba24b38177 100644
--- a/libc/src/stdlib/str_from_util.h
+++ b/libc/src/stdlib/str_from_util.h
@@ -104,8 +104,8 @@ printf_core::FormatSection parse_format_string(const char *__restrict format,
return section;
}
-template <typename T>
-int strfromfloat_convert(printf_core::Writer *writer,
+template <typename T, printf_core::WriteMode write_mode>
+int strfromfloat_convert(printf_core::Writer<write_mode> *writer,
const printf_core::FormatSection §ion) {
if (!section.has_conv)
return writer->write(section.raw_string);
diff --git a/libc/src/stdlib/strfromd.cpp b/libc/src/stdlib/strfromd.cpp
index 4c51e4c5c8a011..7e03f25cdc5901 100644
--- a/libc/src/stdlib/strfromd.cpp
+++ b/libc/src/stdlib/strfromd.cpp
@@ -19,8 +19,9 @@ LLVM_LIBC_FUNCTION(int, strfromd,
printf_core::FormatSection section =
internal::parse_format_string(format, fp);
- printf_core::WriteBuffer wb(s, (n > 0 ? n - 1 : 0));
- printf_core::Writer writer(&wb);
+ printf_core::WriteBuffer<printf_core::WriteMode::FILL_BUFF_AND_DROP_OVERFLOW>
+ wb(s, (n > 0 ? n - 1 : 0));
+ printf_core::Writer writer(wb);
int result = 0;
if (section.has_conv)
diff --git a/libc/src/stdlib/strfromf.cpp b/libc/src/stdlib/strfromf.cpp
index ea98a69ee4d608..488ff19caa1f0b 100644
--- a/libc/src/stdlib/strfromf.cpp
+++ b/libc/src/stdlib/strfromf.cpp
@@ -19,8 +19,9 @@ LLVM_LIBC_FUNCTION(int, strfromf,
printf_core::FormatSection section =
internal::parse_format_string(format, fp);
- printf_core::WriteBuffer wb(s, (n > 0 ? n - 1 : 0));
- printf_core::Writer writer(&wb);
+ printf_core::WriteBuffer<printf_core::WriteMode::FILL_BUFF_AND_DROP_OVERFLOW>
+ wb(s, (n > 0 ? n - 1 : 0));
+ printf_core::Writer writer(wb);
int result = 0;
if (section.has_conv)
diff --git a/libc/src/stdlib/strfroml.cpp b/libc/src/stdlib/strfroml.cpp
index d5bee7609f69ca..259dba95395ab0 100644
--- a/libc/src/stdlib/strfroml.cpp
+++ b/libc/src/stdlib/strfroml.cpp
@@ -24,8 +24,9 @@ LLVM_LIBC_FUNCTION(int, strfroml,
// the length modifier has to be set to LenghtModifier::L
section.length_modifier = printf_core::LengthModifier::L;
- printf_core::WriteBuffer wb(s, (n > 0 ? n - 1 : 0));
- printf_core::Writer writer(&wb);
+ printf_core::WriteBuffer<printf_core::WriteMode::FILL_BUFF_AND_DROP_OVERFLOW>
+ wb(s, (n > 0 ? n - 1 : 0));
+ printf_core::Writer writer(wb);
int result = 0;
if (section.has_conv)
diff --git a/libc/test/src/stdio/printf_core/converter_test.cpp b/libc/test/src/stdio/printf_core/converter_test.cpp
index 9da749f3b8ad1a..96a00ae598ec22 100644
--- a/libc/test/src/stdio/printf_core/converter_test.cpp
+++ b/libc/test/src/stdio/printf_core/converter_test.cpp
@@ -18,10 +18,14 @@ class LlvmLibcPrintfConverterTest : public LIBC_NAMESPACE::testing::Test {
// void TearDown() override {}
char str[60];
- LIBC_NAMESPACE::printf_core::WriteBuffer wb =
- LIBC_NAMESPACE::printf_core::WriteBuffer(str, sizeof(str) - 1);
- LIBC_NAMESPACE::printf_core::Writer writer =
- LIBC_NAMESPACE::printf_core::Writer(&wb);
+ LIBC_NAMESPACE::printf_core::WriteBuffer<
+ LIBC_NAMESPACE::printf_core::WriteMode::FILL_BUFF_AND_DROP_OVERFLOW>
+ wb = LIBC_NAMESPACE::printf_core::WriteBuffer<
+ LIBC_NAMESPACE::printf_core::WriteMode::FILL_BUFF_AND_DROP_OVERFLOW>(
+ str, sizeof(str) - 1);
+ LIBC_NAMESPACE::printf_core::Writer<
+ LIBC_NAMESPACE::printf_core::WriteMode::FILL_BUFF_AND_DROP_OVERFLOW>
+ writer = LIBC_NAMESPACE::printf_core::Writer(wb);
};
TEST_F(LlvmLibcPrintfConverterTest, SimpleRawConversion) {
diff --git a/libc/test/src/stdio/printf_core/writer_test.cpp b/libc/test/src/stdio/printf_core/writer_test.cpp
index 4fe5ffb4aa9891..8611caa2dfa58d 100644
--- a/libc/test/src/stdio/printf_core/writer_test.cpp
+++ b/libc/test/src/stdio/printf_core/writer_test.cpp
@@ -15,19 +15,20 @@
using LIBC_NAMESPACE::cpp::string_view;
using LIBC_NAMESPACE::printf_core::WriteBuffer;
+using LIBC_NAMESPACE::printf_core::WriteMode;
using LIBC_NAMESPACE::printf_core::Writer;
TEST(LlvmLibcPrintfWriterTest, Constructor) {
char str[10];
- WriteBuffer wb(str, sizeof(str) - 1);
- Writer writer(&wb);
+ WriteBuffer<WriteMode::FILL_BUFF_AND_DROP_OVERFLOW> wb(str, sizeof(str) - 1);
+ Writer writer(wb);
(void)writer;
}
TEST(LlvmLibcPrintfWriterTest, Write) {
char str[4] = {'D', 'E', 'F', 'G'};
- WriteBuffer wb(str, sizeof(str) - 1);
- Writer writer(&wb);
+ WriteBuffer<WriteMode::FILL_BUFF_AND_DROP_OVERFLOW> wb(str, sizeof(str) - 1);
+ Writer writer(wb);
writer.write({"abc", 3});
EXPECT_EQ(str[3], 'G');
@@ -42,8 +43,8 @@ TEST(LlvmLibcPrintfWriterTest, Write) {
TEST(LlvmLibcPrintfWriterTest, WriteMultipleTimes) {
char str[10];
- WriteBuffer wb(str, sizeof(str) - 1);
- Writer writer(&wb);
+ WriteBuffer<WriteMode::FILL_BUFF_AND_DROP_OVERFLOW> wb(str, sizeof(str) - 1);
+ Writer writer(wb);
writer.write({"abc", 3});
writer.write({"DEF", 3});
writer.write({"1234", 3});
@@ -56,8 +57,8 @@ TEST(LlvmLibcPrintfWriterTest, WriteMultipleTimes) {
TEST(LlvmLibcPrintfWriterTest, WriteChars) {
char str[4] = {'D', 'E', 'F', 'G'};
- WriteBuffer wb(str, sizeof(str) - 1);
- Writer writer(&wb);
+ WriteBuffer<WriteMode::FILL_BUFF_AND_DROP_OVERFLOW> wb(str, sizeof(str) - 1);
+ Writer writer(wb);
writer.write('a', 3);
EXPECT_EQ(str[3], 'G');
@@ -69,8 +70,8 @@ TEST(LlvmLibcPrintfWriterTest, WriteChars) {
TEST(LlvmLibcPrintfWriterTest, WriteCharsMultipleTimes) {
char str[10];
- WriteBuffer wb(str, sizeof(str) - 1);
- Writer writer(&wb);
+ WriteBuffer<WriteMode::FILL_BUFF_AND_DROP_OVERFLOW> wb(str, sizeof(str) - 1);
+ Writer writer(wb);
writer.write('a', 3);
writer.write('D', 3);
writer.write('1', 3);
@@ -83,8 +84,8 @@ TEST(LlvmLibcPrintfWriterTest, WriteCharsMultipleTimes) {
TEST(LlvmLibcPrintfWriterTest, WriteManyChars) {
char str[100];
- WriteBuffer wb(str, sizeof(str) - 1);
- Writer writer(&wb);
+ WriteBuffer<WriteMode::FILL_BUFF_AND_DROP_OVERFLOW> wb(str, sizeof(str) - 1);
+ Writer writer(wb);
writer.write('Z', 99);
wb.buff[wb.buff_cur] = '\0';
@@ -105,8 +106,8 @@ TEST(LlvmLibcPrintfWriterTest, WriteManyChars) {
TEST(LlvmLibcPrintfWriterTest, MixedWrites) {
char str[13];
- WriteBuffer wb(str, sizeof(str) - 1);
- Writer writer(&wb);
+ WriteBuffer<WriteMode::FILL_BUFF_AND_DROP_OVERFLOW> wb(str, sizeof(str) - 1);
+ Writer writer(wb);
writer.write('a', 3);
writer.write({"DEF", 3});
writer.write('1', 3);
@@ -120,8 +121,8 @@ TEST(LlvmLibcPrintfWriterTest, MixedWrites) {
TEST(LlvmLibcPrintfWriterTest, WriteWithMaxLength) {
char str[11];
- WriteBuffer wb(str, sizeof(str) - 1);
- Writer writer(&wb);
+ WriteBuffer<WriteMode::FILL_BUFF_AND_DROP_OVERFLOW> wb(str, sizeof(str) - 1);
+ Writer writer(wb);
writer.write({"abcDEF123456", 12});
wb.buff[wb.buff_cur] = '\0';
@@ -132,8 +133,8 @@ TEST(LlvmLibcPrintfWriterTest, WriteWithMaxLength) {
TEST(LlvmLibcPrintfWriterTest, WriteCharsWithMaxLength) {
char str[11];
- WriteBuffer wb(str, sizeof(str) - 1);
- Writer writer(&wb);
+ WriteBuffer<WriteMode::FILL_BUFF_AND_DROP_OVERFLOW> wb(str, sizeof(str) - 1);
+ Writer writer(wb);
writer.write('1', 15);
wb.buff[wb.buff_cur] = '\0';
@@ -144,9 +145,9 @@ TEST(LlvmLibcPrintfWriterTest, WriteCharsWithMaxLength) {
TEST(LlvmLibcPrintfWriterTest, MixedWriteWithMaxLength) {
char str[11];
- WriteBuffer wb(str, sizeof(str) - 1);
+ WriteBuffer<WriteMode::FILL_BUFF_AND_DROP_OVERFLOW> wb(str, sizeof(str) - 1);
- Writer writer(&wb);
+ Writer writer(wb);
writer.write('a', 3);
writer.write({"DEF", 3});
writer.write('1', 3);
@@ -162,9 +163,9 @@ TEST(LlvmLibcPrintfWriterTest, StringWithMaxLengthOne) {
char str[1];
// This is because the max length should be at most 1 less than the size of
// the buffer it's writing to.
- WriteBuffer wb(str, 0);
+ WriteBuffer<WriteMode::FILL_BUFF_AND_DROP_OVERFLOW> wb(str, 0);
- Writer writer(&wb);
+ Writer writer(wb);
writer.write('a', 3);
writer.write({"DEF", 3});
writer.write('1', 3);
@@ -177,9 +178,9 @@ TEST(LlvmLibcPrintfWriterTest, StringWithMaxLengthOne) {
}
TEST(LlvmLibcPrintfWriterTest, NullStringWithZeroMaxLength) {
- WriteBuffer wb(nullptr, 0);
+ WriteBuffer<WriteMode::FILL_BUFF_AND_DROP_OVERFLOW> wb(nullptr, 0);
- Writer writer(&wb);
+ Writer writer(wb);
writer.write('a', 3);
writer.write({"DEF", 3});
writer.write('1', 3);
@@ -213,9 +214,10 @@ TEST(LlvmLibcPrintfWriterTest, WriteWithMaxLengthWithCallback) {
OutBuff out_buff = {str, 0};
char wb_buff[8];
- WriteBuffer wb(wb_buff, sizeof(wb_buff), ©_to_out,
- reinterpret_cast<void *>(&out_buff));
- Writer writer(&wb);
+ WriteBuffer<WriteMode::FLUSH_TO_STREAM> wb(
+ wb_buff, sizeof(wb_buff), ©_to_out,
+ reinterpret_cast<void *>(&out_buff));
+ Writer writer(wb);
writer.write({"abcDEF123456", 12});
// Flush the buffer
@@ -232,9 +234,10 @@ TEST(LlvmLibcPrintfWriterTest, WriteCharsWithMaxLengthWithCallback) {
OutBuff out_buff = {str, 0};
char wb_buff[8];
- WriteBuffer wb(wb_buff, sizeof(wb_buff), ©_to_out,
- reinterpret_cast<void *>(&out_buff));
- Writer writer(&wb);
+ WriteBuffer<WriteMode::FLUSH_TO_STREAM> wb(
+ wb_buff, sizeof(wb_buff), ©_to_out,
+ reinterpret_cast<void *>(&out_buff));
+ Writer writer(wb);
writer.write('1', 15);
// Flush the buffer
@@ -251,9 +254,10 @@ TEST(LlvmLibcPrintfWriterTest, MixedWriteWithMaxLengthWithCallback) {
OutBuff out_buff = {str, 0};
char wb_buff[8];
- WriteBuffer wb(wb_buff, sizeof(wb_buff), ©_to_out,
- reinterpret_cast<void *>(&out_buff));
- Writer writer(&wb);
+ WriteBuffer<WriteMode::FLUSH_TO_STREAM> wb(
+ wb_buff, sizeof(wb_buff), ©_to_out,
+ reinterpret_cast<void *>(&out_buff));
+ Writer writer(wb);
writer.write('a', 3);
writer.write({"DEF", 3});
writer.write('1', 3);
@@ -273,9 +277,10 @@ TEST(LlvmLibcPrintfWriterTest, ZeroLengthBufferWithCallback) {
OutBuff out_buff = {str, 0};
char wb_buff[1];
- WriteBuffer wb(wb_buff, 0, ©_to_out, reinterpret_cast<void *>(&out_buff));
+ WriteBuffer<WriteMode::FLUSH_TO_STREAM> wb(
+ wb_buff, 0, ©_to_out, reinterpret_cast<void *>(&out_buff));
- Writer writer(&wb);
+ Writer writer(wb);
writer.write('a', 3);
writer.write({"DEF", 3});
writer.write('1', 3);
@@ -294,9 +299,10 @@ TEST(LlvmLibcPrintfWriterTest, NullStringWithZeroMaxLengthWithCallback) {
OutBuff out_buff = {str, 0};
- WriteBuffer wb(nullptr, 0, ©_to_out, reinterpret_cast<void *>(&out_buff));
+ WriteBuffer<WriteMode::FLUSH_TO_STREAM> wb(
+ nullptr, 0, ©_to_out, reinterpret_cast<void *>(&out_buff));
- Writer writer(&wb);
+ Writer writer(wb);
writer.write('a', 3);
writer.write({"DEF", 3});
writer.write('1', 3);
diff --git a/libc/utils/gpu/server/CMakeLists.txt b/libc/utils/gpu/server/CMakeLists.txt
index 50056fb376b699..01e0b62eb0ebcf 100644
--- a/libc/utils/gpu/server/CMakeLists.txt
+++ b/libc/utils/gpu/server/CMakeLists.txt
@@ -1,8 +1,4 @@
-add_library(llvmlibc_rpc_server STATIC
- ${LIBC_SOURCE_DIR}/src/stdio/printf_core/writer.cpp
- ${LIBC_SOURCE_DIR}/src/stdio/printf_core/converter.cpp
- rpc_server.cpp
-)
+add_library(llvmlibc_rpc_server STATIC rpc_server.cpp)
# Include the RPC implemenation from libc.
target_include_directories(llvmlibc_rpc_server PRIVATE ${LIBC_SOURCE_DIR})
diff --git a/libc/utils/gpu/server/rpc_server.cpp b/libc/utils/gpu/server/rpc_server.cpp
index ca10e67509ae63..cd393effd01778 100644
--- a/libc/utils/gpu/server/rpc_server.cpp
+++ b/libc/utils/gpu/server/rpc_server.cpp
@@ -83,8 +83,8 @@ static void handle_printf(rpc::Server::Port &port, TempStorage &temp_storage) {
if (!format[lane])
continue;
- WriteBuffer wb(nullptr, 0);
- Writer writer(&wb);
+ WriteBuffer<WriteMode::FILL_BUFF_AND_DROP_OVERFLOW> wb(nullptr, 0);
+ Writer writer(wb);
internal::DummyArgList<packed> printf_args;
Parser<internal::DummyArgList<packed> &> parser(
@@ -110,8 +110,8 @@ static void handle_printf(rpc::Server::Port &port, TempStorage &temp_storage) {
if (!format[lane])
continue;
- WriteBuffer wb(nullptr, 0);
- Writer writer(&wb);
+ WriteBuffer<WriteMode::FILL_BUFF_AND_DROP_OVERFLOW> wb(nullptr, 0);
+ Writer writer(wb);
internal::StructArgList<packed> printf_args(args[lane], args_sizes[lane]);
Parser<internal::StructArgList<packed>> parser(
@@ -167,8 +167,9 @@ static void handle_printf(rpc::Server::Port &port, TempStorage &temp_storage) {
continue;
char *buffer = temp_storage.alloc(buffer_size[lane]);
- WriteBuffer wb(buffer, buffer_size[lane]);
- Writer writer(&wb);
+ WriteBuffer<WriteMode::FILL_BUFF_AND_DROP_OVERFLOW> wb(buffer,
+ buffer_size[lane]);
+ Writer writer(wb);
internal::StructArgList<packed> printf_args(args[lane], args_sizes[lane]);
Parser<internal::StructArgList<packed>> parser(
More information about the libc-commits
mailing list