[libc] Add option to disable printf bit int (#180832)

Requested as a binary size optimization. Updates the parser, converter
utils, config, tests, and docs.
This commit is contained in:
Michael Jones
2026-02-10 15:41:38 -08:00
committed by GitHub
parent 59bcec2685
commit ac1220f860
12 changed files with 52 additions and 4 deletions

View File

@@ -151,6 +151,10 @@ function(_get_compile_options_from_config output_var)
list(APPEND config_options "-DLIBC_COPT_PRINTF_DISABLE_WIDE")
endif()
if(LIBC_COPT_PRINTF_DISABLE_BITINT)
list(APPEND config_options "-DLIBC_COPT_PRINTF_DISABLE_BITINT")
endif()
set(${output_var} ${config_options} PARENT_SCOPE)
endfunction(_get_compile_options_from_config)

View File

@@ -28,7 +28,10 @@
"LIBC_CONF_PRINTF_DISABLE_STRERROR": {
"value": true
},
"LIBC_CONF_PRINTF_DISABLE_WIDE" : {
"LIBC_CONF_PRINTF_DISABLE_WIDE": {
"value": true
},
"LIBC_COPT_PRINTF_DISABLE_BITINT": {
"value": true
}
},

View File

@@ -40,7 +40,6 @@
"value": false,
"doc": "Use an alternative printf float implementation based on 320-bit floats"
},
"LIBC_CONF_PRINTF_DISABLE_FIXED_POINT": {
"value": false,
"doc": "Disable printing fixed point values in printf and friends."
@@ -56,6 +55,10 @@
"LIBC_CONF_PRINTF_DISABLE_WIDE": {
"value": false,
"doc": "Disable handling wide characters for printf and friends."
},
"LIBC_COPT_PRINTF_DISABLE_BITINT": {
"value": false,
"doc": "Disable bitint length modifiers to reduce code size. Specifically the wNUM and wfNUM modifiers."
}
},
"scanf": {

View File

@@ -50,6 +50,7 @@ to learn about the defaults for your platform and target.
- ``LIBC_CONF_PRINTF_FLOAT_TO_STR_USE_FLOAT320``: Use an alternative printf float implementation based on 320-bit floats
- ``LIBC_CONF_PRINTF_FLOAT_TO_STR_USE_MEGA_LONG_DOUBLE_TABLE``: Use large table for better printf long double performance.
- ``LIBC_CONF_PRINTF_RUNTIME_DISPATCH``: Use dynamic dispatch for the output mechanism to reduce code size.
- ``LIBC_COPT_PRINTF_DISABLE_BITINT``: Disable bitint length modifiers to reduce code size. Specifically the wNUM and wfNUM modifiers.
* **"pthread" options**
- ``LIBC_CONF_RAW_MUTEX_DEFAULT_SPIN_COUNT``: Default number of spins before blocking if a mutex is in contention (default to 100).
- ``LIBC_CONF_RWLOCK_DEFAULT_SPIN_COUNT``: Default number of spins before blocking if a rwlock is in contention (default to 100).

View File

@@ -72,12 +72,18 @@ invalid. This reduces code size. This has no effect if the current compiler does
not support fixed point numbers.
LIBC_COPT_PRINTF_DISABLE_WIDE
--------------------------------
-----------------------------
When set, this flag disables support for wide characters (%lc and %ls). Any
conversions will be ignored. This reduces code size. This will be set by default
on windows platforms as current printf implementation does not support UTF-16 wide
characters.
LIBC_COPT_PRINTF_DISABLE_BITINT
-------------------------------
When set, this flag disables the bit int length modifiers wNUM and wfNUM. The
length modifiers will be treated as if they don't exist, so conversions using
them will be treated as invalid. This reduces code size.
.. _printf_no_nullptr_checks:
LIBC_COPT_PRINTF_NO_NULLPTR_CHECKS

View File

@@ -43,6 +43,7 @@ LIBC_INLINE uintmax_t apply_length_modifier(uintmax_t num,
return num & cpp::numeric_limits<uintptr_t>::max();
case LengthModifier::j:
return num; // j is intmax, so no mask is necessary.
#ifndef LIBC_COPT_PRINTF_DISABLE_BITINT
case LengthModifier::w:
case LengthModifier::wf: {
uintmax_t mask;
@@ -55,6 +56,7 @@ LIBC_INLINE uintmax_t apply_length_modifier(uintmax_t num,
}
return num & mask;
}
#endif // LIBC_COPT_PRINTF_DISABLE_BITINT
}
__builtin_unreachable();
}

View File

@@ -24,7 +24,21 @@ namespace printf_core {
// These length modifiers match the length modifiers in the format string, which
// is why they are formatted differently from the rest of the file.
enum class LengthModifier { hh, h, l, ll, j, z, t, L, w, wf, none };
enum class LengthModifier {
hh,
h,
l,
ll,
j,
z,
t,
L,
#ifndef LIBC_COPT_PRINTF_DISABLE_BITINT
w,
wf,
#endif // LIBC_COPT_PRINTF_DISABLE_BITINT
none
};
struct LengthSpec {
LengthModifier lm;

View File

@@ -224,6 +224,7 @@ public:
WRITE_ARG_VAL_SIMPLEST(section.conv_val_raw, ptrdiff_t, conv_index);
break;
#ifndef LIBC_COPT_PRINTF_DISABLE_BITINT
case (LengthModifier::w):
case (LengthModifier::wf):
if (bw == 0) {
@@ -238,6 +239,7 @@ public:
WRITE_ARG_VAL_SIMPLEST(section.conv_val_raw, intmax_t, conv_index);
}
break;
#endif // LIBC_COPT_PRINTF_DISABLE_BITINT
}
break;
#ifndef LIBC_COPT_PRINTF_DISABLE_FLOAT
@@ -360,6 +362,7 @@ private:
++*local_pos;
return {LengthModifier::l, 0};
}
#ifndef LIBC_COPT_PRINTF_DISABLE_BITINT
case ('w'): {
LengthModifier lm;
if (str[*local_pos + 1] == 'f') {
@@ -376,6 +379,7 @@ private:
}
return {lm, 0};
}
#endif // LIBC_COPT_PRINTF_DISABLE_BITINT
case ('h'):
if (str[*local_pos + 1] == 'h') {
*local_pos += 2;
@@ -629,6 +633,7 @@ private:
case (LengthModifier::t):
conv_size = type_desc_from_type<ptrdiff_t>();
break;
#ifndef LIBC_COPT_PRINTF_DISABLE_BITINT
case (LengthModifier::w):
case (LengthModifier::wf):
if (bw <= cpp::numeric_limits<unsigned int>::digits) {
@@ -641,6 +646,7 @@ private:
conv_size = type_desc_from_type<intmax_t>();
}
break;
#endif // LIBC_COPT_PRINTF_DISABLE_BITINT
}
break;
#ifndef LIBC_COPT_PRINTF_DISABLE_FLOAT

View File

@@ -57,8 +57,10 @@ LIBC_INLINE int convert_write_int(Writer<write_mode> *writer,
*reinterpret_cast<ptrdiff_t *>(to_conv.conv_val_ptr) = written;
break;
case LengthModifier::j:
#ifndef LIBC_COPT_PRINTF_DISABLE_BITINT
case LengthModifier::w:
case LengthModifier::wf:
#endif // LIBC_COPT_PRINTF_DISABLE_BITINT
*reinterpret_cast<uintmax_t *>(to_conv.conv_val_ptr) = written;
break;
}

View File

@@ -71,8 +71,10 @@ static void display(FormatSection form) {
CASE_LM(z);
CASE_LM(t);
CASE_LM(L);
#ifndef LIBC_COPT_PRINTF_DISABLE_BITINT
CASE_LM_BIT_WIDTH(w, form.bit_width);
CASE_LM_BIT_WIDTH(wf, form.bit_width);
#endif // LIBC_COPT_PRINTF_DISABLE_BITINT
}
tlog << "\n";
tlog << "\tconversion name: " << form.conv_name << "\n";

View File

@@ -230,6 +230,7 @@ TEST(LlvmLibcPrintfParserTest, EvalOneArgWithLongLengthModifier) {
ASSERT_PFORMAT_EQ(expected, format_arr[0]);
}
#ifndef LIBC_COPT_PRINTF_DISABLE_BITINT
TEST(LlvmLibcPrintfParserTest, EvalOneArgWithBitWidthLengthModifier) {
LIBC_NAMESPACE::printf_core::FormatSection format_arr[10];
const char *str = "%w32d";
@@ -267,6 +268,7 @@ TEST(LlvmLibcPrintfParserTest, EvalOneArgWithFastBitWidthLengthModifier) {
ASSERT_PFORMAT_EQ(expected, format_arr[0]);
}
#endif // LIBC_COPT_PRINTF_DISABLE_BITINT
TEST(LlvmLibcPrintfParserTest, EvalOneArgWithAllOptions) {
LIBC_NAMESPACE::printf_core::FormatSection format_arr[10];

View File

@@ -151,6 +151,8 @@ TEST(LlvmLibcSPrintfTest, IntConv) {
written = LIBC_NAMESPACE::sprintf(buff, "%lld", -9223372036854775807ll - 1ll);
ASSERT_STREQ_LEN(written, buff, "-9223372036854775808"); // ll min
#ifndef LIBC_COPT_PRINTF_DISABLE_BITINT
// Bit int width tests
written = LIBC_NAMESPACE::sprintf(buff, "%w3d", 5807);
ASSERT_STREQ_LEN(written, buff, "7");
@@ -218,6 +220,7 @@ TEST(LlvmLibcSPrintfTest, IntConv) {
written = LIBC_NAMESPACE::sprintf(buff, "%wf999d", 9223372036854775807ll);
ASSERT_STREQ_LEN(written, buff, "9223372036854775807");
#endif // LIBC_COPT_PRINTF_DISABLE_BITINT
// Min Width Tests.