Skip to content

Commit 3510082

Browse files
[libc] move to combined integer converter
The functions converting integers into decimal, hexadecimal, and octal, are all very similar. This patch moves to a combined converter to save code size. Reviewed By: sivachandra Differential Revision: https://reviews.llvm.org/D131302
1 parent 42e2946 commit 3510082

File tree

8 files changed

+72
-283
lines changed

8 files changed

+72
-283
lines changed

libc/src/stdio/printf_core/CMakeLists.txt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,9 +63,7 @@ add_object_library(
6363
string_converter.h
6464
char_converter.h
6565
int_converter.h
66-
hex_converter.h
6766
ptr_converter.h
68-
oct_converter.h
6967
write_int_converter.h
7068
float_inf_nan_converter.h
7169
float_hex_converter.h
@@ -74,6 +72,7 @@ add_object_library(
7472
.core_structs
7573
libc.src.__support.integer_to_string
7674
libc.src.__support.CPP.limits
75+
libc.src.__support.CPP.string_view
7776
libc.src.__support.FPUtil.fputil
7877
)
7978

libc/src/stdio/printf_core/converter.cpp

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,10 @@ int convert(Writer *writer, const FormatSection &to_conv) {
3838
case 'd':
3939
case 'i':
4040
case 'u':
41-
return convert_int(writer, to_conv);
4241
case 'o':
43-
return convert_oct(writer, to_conv);
4442
case 'x':
4543
case 'X':
46-
return convert_hex(writer, to_conv);
44+
return convert_int(writer, to_conv);
4745
#ifndef LLVM_LIBC_PRINTF_DISABLE_FLOAT
4846
// case 'f':
4947
// case 'F':

libc/src/stdio/printf_core/converter_atlas.h

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,6 @@
2222
// defines convert_int
2323
#include "src/stdio/printf_core/int_converter.h"
2424

25-
// defines convert_oct
26-
#include "src/stdio/printf_core/oct_converter.h"
27-
// defines convert_hex
28-
#include "src/stdio/printf_core/hex_converter.h"
29-
3025
#ifndef LLVM_LIBC_PRINTF_DISABLE_FLOAT
3126
// defines convert_float_decimal
3227
// defines convert_float_dec_exp

libc/src/stdio/printf_core/core_structs.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ constexpr int WRITE_OK = 0;
8686
constexpr int FILE_WRITE_ERROR = -1;
8787
constexpr int FILE_STATUS_ERROR = -2;
8888
constexpr int NULLPTR_WRITE_ERROR = -3;
89+
constexpr int INT_CONVERSION_ERROR = -4;
8990

9091
} // namespace printf_core
9192
} // namespace __llvm_libc

libc/src/stdio/printf_core/hex_converter.h

Lines changed: 0 additions & 133 deletions
This file was deleted.

libc/src/stdio/printf_core/int_converter.h

Lines changed: 67 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
#ifndef LLVM_LIBC_SRC_STDIO_PRINTF_CORE_INT_CONVERTER_H
1010
#define LLVM_LIBC_SRC_STDIO_PRINTF_CORE_INT_CONVERTER_H
1111

12+
#include "src/__support/CPP/ArrayRef.h"
13+
#include "src/__support/CPP/StringView.h"
1214
#include "src/__support/integer_to_string.h"
1315
#include "src/stdio/printf_core/converter_utils.h"
1416
#include "src/stdio/printf_core/core_structs.h"
@@ -20,6 +22,23 @@
2022
namespace __llvm_libc {
2123
namespace printf_core {
2224

25+
// These functions only work on characters that are already known to be in the
26+
// alphabet. Their behavior is undefined otherwise.
27+
constexpr char inline to_lower(char a) { return a | 32; }
28+
constexpr bool inline is_lower(char a) { return (a & 32) > 0; }
29+
30+
cpp::optional<cpp::StringView> inline num_to_strview(
31+
uintmax_t num, cpp::MutableArrayRef<char> bufref, char conv_name) {
32+
if (to_lower(conv_name) == 'x') {
33+
return IntegerToString<uintmax_t, 16>::convert(num, bufref,
34+
is_lower(conv_name));
35+
} else if (conv_name == 'o') {
36+
return IntegerToString<uintmax_t, 8>::convert(num, bufref, true);
37+
} else {
38+
return IntegerToString<uintmax_t, 10>::convert(num, bufref, true);
39+
}
40+
}
41+
2342
int inline convert_int(Writer *writer, const FormatSection &to_conv) {
2443
static constexpr size_t BITS_IN_BYTE = 8;
2544
static constexpr size_t BITS_IN_NUM = sizeof(uintmax_t) * BITS_IN_BYTE;
@@ -28,24 +47,33 @@ int inline convert_int(Writer *writer, const FormatSection &to_conv) {
2847
bool is_negative = false;
2948
FormatFlags flags = to_conv.flags;
3049

31-
if (to_conv.conv_name == 'u') {
32-
// These flags are only for signed conversions, so this removes them if the
33-
// conversion is unsigned.
34-
flags = FormatFlags(flags &
35-
~(FormatFlags::FORCE_SIGN | FormatFlags::SPACE_PREFIX));
36-
} else {
50+
const char a = is_lower(to_conv.conv_name) ? 'a' : 'A';
51+
52+
// If the conversion is signed, then handle negative values.
53+
if (to_conv.conv_name == 'd' || to_conv.conv_name == 'i') {
3754
// Check if the number is negative by checking the high bit. This works even
3855
// for smaller numbers because they're sign extended by default.
3956
if ((num & (uintmax_t(1) << (BITS_IN_NUM - 1))) > 0) {
4057
is_negative = true;
4158
num = -num;
4259
}
60+
} else {
61+
// These flags are only for signed conversions, so this removes them if the
62+
// conversion is unsigned.
63+
flags = FormatFlags(flags &
64+
~(FormatFlags::FORCE_SIGN | FormatFlags::SPACE_PREFIX));
4365
}
4466

4567
num = apply_length_modifier(num, to_conv.length_modifier);
4668

47-
auto const int_to_str = integer_to_string(num);
48-
size_t digits_written = int_to_str.str().size();
69+
static constexpr size_t BUFSIZE = IntegerToString<uintmax_t, 8>::BUFSIZE;
70+
char buff[BUFSIZE];
71+
cpp::MutableArrayRef<char> bufref(buff, BUFSIZE);
72+
auto str = num_to_strview(num, bufref, to_conv.conv_name);
73+
if (!str)
74+
return INT_CONVERSION_ERROR;
75+
76+
size_t digits_written = str->size();
4977

5078
char sign_char = 0;
5179

@@ -56,29 +84,39 @@ int inline convert_int(Writer *writer, const FormatSection &to_conv) {
5684
else if ((flags & FormatFlags::SPACE_PREFIX) == FormatFlags::SPACE_PREFIX)
5785
sign_char = ' ';
5886

59-
int sign_char_len = (sign_char == 0 ? 0 : 1);
60-
6187
// These are signed to prevent underflow due to negative values. The eventual
6288
// values will always be non-negative.
6389
int zeroes;
6490
int spaces;
6591

92+
// prefix is "0x" for hexadecimal, or the sign character for signed
93+
// conversions. Since hexadecimal is unsigned these will never conflict.
94+
int prefix_len;
95+
char prefix[2];
96+
if ((to_lower(to_conv.conv_name) == 'x') &&
97+
((flags & FormatFlags::ALTERNATE_FORM) != 0)) {
98+
prefix_len = 2;
99+
prefix[0] = '0';
100+
prefix[1] = a + ('x' - 'a');
101+
} else {
102+
prefix_len = (sign_char == 0 ? 0 : 1);
103+
prefix[0] = sign_char;
104+
}
105+
66106
// Negative precision indicates that it was not specified.
67107
if (to_conv.precision < 0) {
68108
if ((flags & (FormatFlags::LEADING_ZEROES | FormatFlags::LEFT_JUSTIFIED)) ==
69109
FormatFlags::LEADING_ZEROES) {
70110
// If this conv has flag 0 but not - and no specified precision, it's
71111
// padded with 0's instead of spaces identically to if precision =
72112
// min_width - (1 if sign_char). For example: ("%+04d", 1) -> "+001"
73-
zeroes = to_conv.min_width - digits_written - sign_char_len;
74-
if (zeroes < 0)
75-
zeroes = 0;
113+
zeroes = to_conv.min_width - digits_written - prefix_len;
76114
spaces = 0;
77115
} else {
78116
// If there are enough digits to pass over the precision, just write the
79117
// number, padded by spaces.
80118
zeroes = 0;
81-
spaces = to_conv.min_width - digits_written - sign_char_len;
119+
spaces = to_conv.min_width - digits_written - prefix_len;
82120
}
83121
} else {
84122
// If precision was specified, possibly write zeroes, and possibly write
@@ -94,33 +132,35 @@ int inline convert_int(Writer *writer, const FormatSection &to_conv) {
94132
zeroes = to_conv.precision - digits_written; // a negative value means 0
95133
if (zeroes < 0)
96134
zeroes = 0;
97-
spaces = to_conv.min_width - zeroes - digits_written - sign_char_len;
135+
spaces = to_conv.min_width - zeroes - digits_written - prefix_len;
136+
}
137+
138+
if ((to_conv.conv_name == 'o') &&
139+
((to_conv.flags & FormatFlags::ALTERNATE_FORM) != 0) && zeroes < 1) {
140+
zeroes = 1;
141+
--spaces;
98142
}
99-
if (spaces < 0)
100-
spaces = 0;
101143

102144
if ((flags & FormatFlags::LEFT_JUSTIFIED) == FormatFlags::LEFT_JUSTIFIED) {
103-
// If left justified it goes sign zeroes digits spaces
104-
if (sign_char != 0)
105-
RET_IF_RESULT_NEGATIVE(writer->write(&sign_char, 1));
145+
// If left justified it goes prefix zeroes digits spaces
146+
if (prefix_len != 0)
147+
RET_IF_RESULT_NEGATIVE(writer->write(prefix, prefix_len));
106148
if (zeroes > 0)
107149
RET_IF_RESULT_NEGATIVE(writer->write_chars('0', zeroes));
108150
if (digits_written > 0)
109-
RET_IF_RESULT_NEGATIVE(
110-
writer->write(int_to_str.str().data(), digits_written));
151+
RET_IF_RESULT_NEGATIVE(writer->write(str->data(), digits_written));
111152
if (spaces > 0)
112153
RET_IF_RESULT_NEGATIVE(writer->write_chars(' ', spaces));
113154
} else {
114-
// Else it goes spaces sign zeroes digits
155+
// Else it goes spaces prefix zeroes digits
115156
if (spaces > 0)
116157
RET_IF_RESULT_NEGATIVE(writer->write_chars(' ', spaces));
117-
if (sign_char != 0)
118-
RET_IF_RESULT_NEGATIVE(writer->write(&sign_char, 1));
158+
if (prefix_len != 0)
159+
RET_IF_RESULT_NEGATIVE(writer->write(prefix, prefix_len));
119160
if (zeroes > 0)
120161
RET_IF_RESULT_NEGATIVE(writer->write_chars('0', zeroes));
121162
if (digits_written > 0)
122-
RET_IF_RESULT_NEGATIVE(
123-
writer->write(int_to_str.str().data(), digits_written));
163+
RET_IF_RESULT_NEGATIVE(writer->write(str->data(), digits_written));
124164
}
125165
return WRITE_OK;
126166
}

0 commit comments

Comments
 (0)