Skip to content

Commit 598e882

Browse files
authored
[libc] Template the writing mode for the writer class (llvm#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.
1 parent 3aa96f5 commit 598e882

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+508
-509
lines changed

libc/config/config.json

+4
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,10 @@
4141
"LIBC_CONF_PRINTF_DISABLE_STRERROR": {
4242
"value": false,
4343
"doc": "Disable handling of %m to print strerror in printf and friends."
44+
},
45+
"LIBC_CONF_PRINTF_RUNTIME_DISPATCH": {
46+
"value": true,
47+
"doc": "Use dynamic dispatch for the output mechanism to reduce code size."
4448
}
4549
},
4650
"scanf": {

libc/config/gpu/amdgpu/config.json

+3
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@
1919
},
2020
"LIBC_CONF_PRINTF_DISABLE_STRERROR": {
2121
"value": true
22+
},
23+
"LIBC_CONF_PRINTF_RUNTIME_DISPATCH": {
24+
"value": false
2225
}
2326
},
2427
"scanf": {

libc/config/gpu/nvptx/config.json

+3
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@
1919
},
2020
"LIBC_CONF_PRINTF_DISABLE_STRERROR": {
2121
"value": true
22+
},
23+
"LIBC_CONF_PRINTF_RUNTIME_DISPATCH": {
24+
"value": false
2225
}
2326
},
2427
"scanf": {

libc/docs/configure.rst

+1
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ to learn about the defaults for your platform and target.
4545
- ``LIBC_CONF_PRINTF_FLOAT_TO_STR_USE_DYADIC_FLOAT``: Use dyadic float for faster and smaller but less accurate printf doubles.
4646
- ``LIBC_CONF_PRINTF_FLOAT_TO_STR_USE_FLOAT320``: Use an alternative printf float implementation based on 320-bit floats
4747
- ``LIBC_CONF_PRINTF_FLOAT_TO_STR_USE_MEGA_LONG_DOUBLE_TABLE``: Use large table for better printf long double performance.
48+
- ``LIBC_CONF_PRINTF_RUNTIME_DISPATCH``: Use dynamic dispatch for the output mechanism to reduce code size.
4849
* **"pthread" options**
4950
- ``LIBC_CONF_RAW_MUTEX_DEFAULT_SPIN_COUNT``: Default number of spins before blocking if a mutex is in contention (default to 100).
5051
- ``LIBC_CONF_RWLOCK_DEFAULT_SPIN_COUNT``: Default number of spins before blocking if a rwlock is in contention (default to 100).

libc/src/stdio/printf_core/CMakeLists.txt

+6-9
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@ endif()
2525
if(LIBC_CONF_PRINTF_DISABLE_STRERROR)
2626
list(APPEND printf_config_copts "-DLIBC_COPT_PRINTF_DISABLE_STRERROR")
2727
endif()
28+
if(LIBC_CONF_PRINTF_RUNTIME_DISPATCH)
29+
list(APPEND printf_config_copts "-DLIBC_COPT_PRINTF_RUNTIME_DISPATCH")
30+
endif()
2831
if(printf_config_copts)
2932
list(PREPEND printf_config_copts "COMPILE_OPTIONS")
3033
endif()
@@ -62,10 +65,8 @@ add_header_library(
6265
libc.src.__support.common
6366
)
6467

65-
add_object_library(
68+
add_header_library(
6669
writer
67-
SRCS
68-
writer.cpp
6970
HDRS
7071
writer.h
7172
DEPENDS
@@ -76,10 +77,8 @@ add_object_library(
7677
libc.src.string.memory_utils.inline_memset
7778
)
7879

79-
add_object_library(
80+
add_header_library(
8081
converter
81-
SRCS
82-
converter.cpp
8382
HDRS
8483
converter.h
8584
converter_atlas.h
@@ -113,10 +112,8 @@ add_object_library(
113112
libc.src.__support.StringUtil.error_to_string
114113
)
115114

116-
add_object_library(
115+
add_header_library(
117116
printf_main
118-
SRCS
119-
printf_main.cpp
120117
HDRS
121118
printf_main.h
122119
DEPENDS

libc/src/stdio/printf_core/char_converter.h

+3-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@
1717
namespace LIBC_NAMESPACE_DECL {
1818
namespace printf_core {
1919

20-
LIBC_INLINE int convert_char(Writer *writer, const FormatSection &to_conv) {
20+
template <WriteMode write_mode>
21+
LIBC_INLINE int convert_char(Writer<write_mode> *writer,
22+
const FormatSection &to_conv) {
2123
char c = static_cast<char>(to_conv.conv_val_raw);
2224

2325
constexpr int STRING_LEN = 1;

libc/src/stdio/printf_core/converter.cpp

-105
This file was deleted.

libc/src/stdio/printf_core/converter.h

+84-1
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,18 @@
1111

1212
#include "src/__support/macros/config.h"
1313
#include "src/stdio/printf_core/core_structs.h"
14+
#include "src/stdio/printf_core/printf_config.h"
15+
#include "src/stdio/printf_core/strerror_converter.h"
1416
#include "src/stdio/printf_core/writer.h"
1517

18+
// This option allows for replacing all of the conversion functions with custom
19+
// replacements. This allows conversions to be replaced at compile time.
20+
#ifndef LIBC_COPT_PRINTF_CONV_ATLAS
21+
#include "src/stdio/printf_core/converter_atlas.h"
22+
#else
23+
#include LIBC_COPT_PRINTF_CONV_ATLAS
24+
#endif
25+
1626
#include <stddef.h>
1727

1828
namespace LIBC_NAMESPACE_DECL {
@@ -21,7 +31,80 @@ namespace printf_core {
2131
// convert will call a conversion function to convert the FormatSection into
2232
// its string representation, and then that will write the result to the
2333
// writer.
24-
int convert(Writer *writer, const FormatSection &to_conv);
34+
template <WriteMode write_mode>
35+
int convert(Writer<write_mode> *writer, const FormatSection &to_conv) {
36+
if (!to_conv.has_conv)
37+
return writer->write(to_conv.raw_string);
38+
39+
#if !defined(LIBC_COPT_PRINTF_DISABLE_FLOAT) && \
40+
defined(LIBC_COPT_PRINTF_HEX_LONG_DOUBLE)
41+
if (to_conv.length_modifier == LengthModifier::L) {
42+
switch (to_conv.conv_name) {
43+
case 'f':
44+
case 'F':
45+
case 'e':
46+
case 'E':
47+
case 'g':
48+
case 'G':
49+
return convert_float_hex_exp(writer, to_conv);
50+
default:
51+
break;
52+
}
53+
}
54+
#endif // LIBC_COPT_PRINTF_DISABLE_FLOAT
55+
56+
switch (to_conv.conv_name) {
57+
case '%':
58+
return writer->write("%");
59+
case 'c':
60+
return convert_char(writer, to_conv);
61+
case 's':
62+
return convert_string(writer, to_conv);
63+
case 'd':
64+
case 'i':
65+
case 'u':
66+
case 'o':
67+
case 'x':
68+
case 'X':
69+
case 'b':
70+
case 'B':
71+
return convert_int(writer, to_conv);
72+
#ifndef LIBC_COPT_PRINTF_DISABLE_FLOAT
73+
case 'f':
74+
case 'F':
75+
return convert_float_decimal(writer, to_conv);
76+
case 'e':
77+
case 'E':
78+
return convert_float_dec_exp(writer, to_conv);
79+
case 'a':
80+
case 'A':
81+
return convert_float_hex_exp(writer, to_conv);
82+
case 'g':
83+
case 'G':
84+
return convert_float_dec_auto(writer, to_conv);
85+
#endif // LIBC_COPT_PRINTF_DISABLE_FLOAT
86+
#ifdef LIBC_INTERNAL_PRINTF_HAS_FIXED_POINT
87+
case 'r':
88+
case 'R':
89+
case 'k':
90+
case 'K':
91+
return convert_fixed(writer, to_conv);
92+
#endif // LIBC_INTERNAL_PRINTF_HAS_FIXED_POINT
93+
#ifndef LIBC_COPT_PRINTF_DISABLE_STRERROR
94+
case 'm':
95+
return convert_strerror(writer, to_conv);
96+
#endif // LIBC_COPT_PRINTF_DISABLE_STRERROR
97+
#ifndef LIBC_COPT_PRINTF_DISABLE_WRITE_INT
98+
case 'n':
99+
return convert_write_int(writer, to_conv);
100+
#endif // LIBC_COPT_PRINTF_DISABLE_WRITE_INT
101+
case 'p':
102+
return convert_pointer(writer, to_conv);
103+
default:
104+
return writer->write(to_conv.raw_string);
105+
}
106+
return -1;
107+
}
25108

26109
} // namespace printf_core
27110
} // namespace LIBC_NAMESPACE_DECL

libc/src/stdio/printf_core/fixed_converter.h

+3-1
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,9 @@ LIBC_INLINE constexpr uint32_t const_ten_exp(uint32_t exponent) {
6363
} \
6464
} while (false)
6565

66-
LIBC_INLINE int convert_fixed(Writer *writer, const FormatSection &to_conv) {
66+
template <WriteMode write_mode>
67+
LIBC_INLINE int convert_fixed(Writer<write_mode> *writer,
68+
const FormatSection &to_conv) {
6769
// Long accum should be the largest type, so we can store all the smaller
6870
// numbers in things sized for it.
6971
using LARep = fixed_point::FXRep<unsigned long accum>;

0 commit comments

Comments
 (0)