[libc-commits] [libc] [libc] Add option to disable printf bit int (PR #180832)
Michael Jones via libc-commits
libc-commits at lists.llvm.org
Tue Feb 10 12:57:15 PST 2026
https://github.com/michaelrj-google created https://github.com/llvm/llvm-project/pull/180832
Requested as a binary size optinization. Updates the parser, converter
utils, config, tests, and docs.
>From c6a738bc9441e290d5d168b8bb8fa9d73a2500e4 Mon Sep 17 00:00:00 2001
From: Michael Jones <michaelrj at google.com>
Date: Tue, 10 Feb 2026 20:09:54 +0000
Subject: [PATCH] [libc] Add option to disable printf bit int
Requested as a binary size optinization. Updates the parser, converter
utils, config, tests, and docs.
---
.../modules/LLVMLibCCompileOptionRules.cmake | 4 ++++
libc/config/baremetal/config.json | 5 ++++-
libc/config/config.json | 5 ++++-
libc/docs/configure.rst | 1 +
libc/docs/dev/printf_behavior.rst | 8 +++++++-
libc/src/stdio/printf_core/converter_utils.h | 2 ++
libc/src/stdio/printf_core/core_structs.h | 16 +++++++++++++++-
libc/src/stdio/printf_core/parser.h | 6 ++++++
libc/src/stdio/printf_core/write_int_converter.h | 2 ++
libc/test/UnitTest/PrintfMatcher.cpp | 2 ++
libc/test/src/stdio/printf_core/parser_test.cpp | 3 +++
libc/test/src/stdio/sprintf_test.cpp | 3 +++
12 files changed, 53 insertions(+), 4 deletions(-)
diff --git a/libc/cmake/modules/LLVMLibCCompileOptionRules.cmake b/libc/cmake/modules/LLVMLibCCompileOptionRules.cmake
index 98fc0206daa44..b15a9fab09c38 100644
--- a/libc/cmake/modules/LLVMLibCCompileOptionRules.cmake
+++ b/libc/cmake/modules/LLVMLibCCompileOptionRules.cmake
@@ -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)
diff --git a/libc/config/baremetal/config.json b/libc/config/baremetal/config.json
index af5b6115c87e0..2c9bfeb20541c 100644
--- a/libc/config/baremetal/config.json
+++ b/libc/config/baremetal/config.json
@@ -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
}
},
diff --git a/libc/config/config.json b/libc/config/config.json
index b37154e294ec9..54d1282df6293 100644
--- a/libc/config/config.json
+++ b/libc/config/config.json
@@ -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": {
diff --git a/libc/docs/configure.rst b/libc/docs/configure.rst
index 0813ab3554216..e6bf4b20ef59e 100644
--- a/libc/docs/configure.rst
+++ b/libc/docs/configure.rst
@@ -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).
diff --git a/libc/docs/dev/printf_behavior.rst b/libc/docs/dev/printf_behavior.rst
index a825da55367bb..4b53e0b85f6d2 100644
--- a/libc/docs/dev/printf_behavior.rst
+++ b/libc/docs/dev/printf_behavior.rst
@@ -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
diff --git a/libc/src/stdio/printf_core/converter_utils.h b/libc/src/stdio/printf_core/converter_utils.h
index 3f25ebfd40ed9..ed656ffb6e72f 100644
--- a/libc/src/stdio/printf_core/converter_utils.h
+++ b/libc/src/stdio/printf_core/converter_utils.h
@@ -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();
}
diff --git a/libc/src/stdio/printf_core/core_structs.h b/libc/src/stdio/printf_core/core_structs.h
index d93fa962db90e..705865745db47 100644
--- a/libc/src/stdio/printf_core/core_structs.h
+++ b/libc/src/stdio/printf_core/core_structs.h
@@ -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;
diff --git a/libc/src/stdio/printf_core/parser.h b/libc/src/stdio/printf_core/parser.h
index a3b62991bcec9..d70a3aa91ce61 100644
--- a/libc/src/stdio/printf_core/parser.h
+++ b/libc/src/stdio/printf_core/parser.h
@@ -224,6 +224,7 @@ template <typename ArgProvider> class Parser {
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 @@ template <typename ArgProvider> class Parser {
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 @@ template <typename ArgProvider> class Parser {
++*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 @@ template <typename ArgProvider> class Parser {
}
return {lm, 0};
}
+#endif // LIBC_COPT_PRINTF_DISABLE_BITINT
case ('h'):
if (str[*local_pos + 1] == 'h') {
*local_pos += 2;
@@ -629,6 +633,7 @@ template <typename ArgProvider> class Parser {
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 @@ template <typename ArgProvider> class Parser {
conv_size = type_desc_from_type<intmax_t>();
}
break;
+#endif // LIBC_COPT_PRINTF_DISABLE_BITINT
}
break;
#ifndef LIBC_COPT_PRINTF_DISABLE_FLOAT
diff --git a/libc/src/stdio/printf_core/write_int_converter.h b/libc/src/stdio/printf_core/write_int_converter.h
index 04b2bef05bc7b..0c7efedb5f3bf 100644
--- a/libc/src/stdio/printf_core/write_int_converter.h
+++ b/libc/src/stdio/printf_core/write_int_converter.h
@@ -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;
}
diff --git a/libc/test/UnitTest/PrintfMatcher.cpp b/libc/test/UnitTest/PrintfMatcher.cpp
index 2ea1bbfcc6360..3a940aad8e435 100644
--- a/libc/test/UnitTest/PrintfMatcher.cpp
+++ b/libc/test/UnitTest/PrintfMatcher.cpp
@@ -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";
diff --git a/libc/test/src/stdio/printf_core/parser_test.cpp b/libc/test/src/stdio/printf_core/parser_test.cpp
index 9d192828860f7..4e1b796ec9b65 100644
--- a/libc/test/src/stdio/printf_core/parser_test.cpp
+++ b/libc/test/src/stdio/printf_core/parser_test.cpp
@@ -230,6 +230,8 @@ 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 +269,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];
diff --git a/libc/test/src/stdio/sprintf_test.cpp b/libc/test/src/stdio/sprintf_test.cpp
index 78186abb9966e..01d9c1056356a 100644
--- a/libc/test/src/stdio/sprintf_test.cpp
+++ b/libc/test/src/stdio/sprintf_test.cpp
@@ -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.
More information about the libc-commits
mailing list