1 //===-- Hexadecimal Converter for printf ------------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8
9 #ifndef LLVM_LIBC_SRC_STDIO_PRINTF_CORE_FLOAT_HEX_CONVERTER_H
10 #define LLVM_LIBC_SRC_STDIO_PRINTF_CORE_FLOAT_HEX_CONVERTER_H
11
12 #include "src/__support/FPUtil/FEnvImpl.h"
13 #include "src/__support/FPUtil/FPBits.h"
14 #include "src/stdio/printf_core/converter_utils.h"
15 #include "src/stdio/printf_core/core_structs.h"
16 #include "src/stdio/printf_core/float_inf_nan_converter.h"
17 #include "src/stdio/printf_core/writer.h"
18
19 #include <inttypes.h>
20 #include <stddef.h>
21
22 namespace __llvm_libc {
23 namespace printf_core {
24
25 using MantissaInt = fputil::FPBits<long double>::UIntType;
26
convert_float_hex_exp(Writer * writer,const FormatSection & to_conv)27 int inline convert_float_hex_exp(Writer *writer, const FormatSection &to_conv) {
28 // All of the letters will be defined relative to variable a, which will be
29 // the appropriate case based on the name of the conversion.
30 // Since the name of the conversion is also 'a', we can just use it directly.
31 const char a = to_conv.conv_name;
32
33 bool is_negative;
34 int exponent;
35 MantissaInt mantissa;
36 bool is_inf_or_nan;
37 uint32_t mantissa_width;
38 int exponent_bias;
39 if (to_conv.length_modifier == LengthModifier::L) {
40 mantissa_width = fputil::MantissaWidth<long double>::VALUE;
41 exponent_bias = fputil::FPBits<long double>::EXPONENT_BIAS;
42 fputil::FPBits<long double>::UIntType float_raw = to_conv.conv_val_raw;
43 fputil::FPBits<long double> float_bits(float_raw);
44 is_negative = float_bits.get_sign();
45 exponent = float_bits.get_exponent();
46 mantissa = float_bits.get_explicit_mantissa();
47 is_inf_or_nan = float_bits.is_inf_or_nan();
48 } else {
49 mantissa_width = fputil::MantissaWidth<double>::VALUE;
50 exponent_bias = fputil::FPBits<double>::EXPONENT_BIAS;
51 fputil::FPBits<double>::UIntType float_raw = to_conv.conv_val_raw;
52 fputil::FPBits<double> float_bits(float_raw);
53 is_negative = float_bits.get_sign();
54 exponent = float_bits.get_exponent();
55 mantissa = float_bits.get_explicit_mantissa();
56 is_inf_or_nan = float_bits.is_inf_or_nan();
57 }
58
59 if (is_inf_or_nan)
60 return convert_inf_nan(writer, to_conv);
61
62 char sign_char = 0;
63
64 if (is_negative)
65 sign_char = '-';
66 else if ((to_conv.flags & FormatFlags::FORCE_SIGN) == FormatFlags::FORCE_SIGN)
67 sign_char = '+'; // FORCE_SIGN has precedence over SPACE_PREFIX
68 else if ((to_conv.flags & FormatFlags::SPACE_PREFIX) ==
69 FormatFlags::SPACE_PREFIX)
70 sign_char = ' ';
71
72 // Handle the exponent for numbers with a 0 exponent
73 if (exponent == -exponent_bias) {
74 if (mantissa > 0) // Subnormals
75 ++exponent;
76 else // Zeroes
77 exponent = 0;
78 }
79
80 constexpr size_t BITS_IN_HEX_DIGIT = 4;
81
82 // This is to handle situations where the mantissa isn't an even number of hex
83 // digits. This is primarily relevant for x86 80 bit long doubles, which have
84 // 63 bit mantissas.
85 if (mantissa_width % BITS_IN_HEX_DIGIT != 0) {
86 exponent -= mantissa_width % BITS_IN_HEX_DIGIT;
87 }
88
89 // This is the max number of digits it can take to represent the mantissa.
90 // Since the number is in bits, we divide by 4, and then add one to account
91 // for the extra implicit bit. We use the larger of the two possible values
92 // since the size must be constant.
93 constexpr size_t MANT_BUFF_LEN =
94 (fputil::MantissaWidth<long double>::VALUE / BITS_IN_HEX_DIGIT) + 1;
95 char mant_buffer[MANT_BUFF_LEN];
96
97 size_t mant_len = (mantissa_width / BITS_IN_HEX_DIGIT) + 1;
98
99 // Precision only tracks the number of digits after the hexadecimal point, so
100 // we have to add one to account for the digit before the hexadecimal point.
101 if (to_conv.precision + 1 < static_cast<int>(mant_len) &&
102 to_conv.precision + 1 > 0) {
103 const size_t intended_digits = to_conv.precision + 1;
104 const size_t shift_amount =
105 (mant_len - intended_digits) * BITS_IN_HEX_DIGIT;
106
107 const MantissaInt truncated_bits =
108 mantissa & ((MantissaInt(1) << shift_amount) - 1);
109 const MantissaInt halfway_const = MantissaInt(1) << (shift_amount - 1);
110
111 mantissa >>= shift_amount;
112
113 switch (fputil::get_round()) {
114 case FE_TONEAREST:
115 // Round to nearest, if it's exactly halfway then round to even.
116 if (truncated_bits > halfway_const)
117 ++mantissa;
118 else if (truncated_bits == halfway_const)
119 mantissa = mantissa + (mantissa & 1);
120 break;
121 case FE_DOWNWARD:
122 if (truncated_bits > 0 && is_negative)
123 ++mantissa;
124 break;
125 case FE_UPWARD:
126 if (truncated_bits > 0 && !is_negative)
127 ++mantissa;
128 break;
129 case FE_TOWARDZERO:
130 break;
131 }
132
133 // If the rounding caused an overflow, shift the mantissa and adjust the
134 // exponent to match.
135 if (mantissa >= (MantissaInt(1) << (intended_digits * BITS_IN_HEX_DIGIT))) {
136 mantissa >>= BITS_IN_HEX_DIGIT;
137 exponent += BITS_IN_HEX_DIGIT;
138 }
139
140 mant_len = intended_digits;
141 }
142
143 size_t mant_cur = mant_len;
144 size_t first_non_zero = 1;
145 for (; mant_cur > 0; --mant_cur, mantissa /= 16) {
146 char new_digit = ((mantissa % 16) > 9) ? ((mantissa % 16) - 10 + a)
147 : ((mantissa % 16) + '0');
148 mant_buffer[mant_cur - 1] = new_digit;
149 if (new_digit != '0' && first_non_zero < mant_cur)
150 first_non_zero = mant_cur;
151 }
152
153 size_t mant_digits = first_non_zero;
154 if (to_conv.precision >= 0)
155 mant_digits = mant_len;
156
157 // This approximates the number of digits it will take to represent the
158 // exponent. The calculation is ceil((bits * 5) / 16). Floor also works, but
159 // only on exact multiples of 16. We add 1 for the sign.
160 // Relevant sizes:
161 // 15 -> 5
162 // 11 -> 4
163 // 8 -> 3
164 constexpr size_t EXP_LEN =
165 (((fputil::ExponentWidth<long double>::VALUE * 5) + 15) / 16) + 1;
166 char exp_buffer[EXP_LEN];
167
168 bool exp_is_negative = false;
169 if (exponent < 0) {
170 exp_is_negative = true;
171 exponent = -exponent;
172 }
173
174 size_t exp_cur = EXP_LEN;
175 for (; exponent > 0; --exp_cur, exponent /= 10) {
176 exp_buffer[exp_cur - 1] = (exponent % 10) + '0';
177 }
178 if (exp_cur == EXP_LEN) { // if nothing else was written, write a 0.
179 exp_buffer[EXP_LEN - 1] = '0';
180 exp_cur = EXP_LEN - 1;
181 }
182
183 exp_buffer[exp_cur - 1] = exp_is_negative ? '-' : '+';
184 --exp_cur;
185
186 // these are signed to prevent underflow due to negative values. The eventual
187 // values will always be non-negative.
188 int trailing_zeroes = 0;
189 int padding;
190
191 // prefix is "0x", and always appears.
192 constexpr size_t PREFIX_LEN = 2;
193 char prefix[PREFIX_LEN];
194 prefix[0] = '0';
195 prefix[1] = a + ('x' - 'a');
196
197 // If the precision is greater than the actual result, pad with 0s
198 if (to_conv.precision > static_cast<int>(mant_digits - 1))
199 trailing_zeroes = to_conv.precision - (mant_digits - 1);
200
201 bool has_hexadecimal_point =
202 (mant_digits > 1) || ((to_conv.flags & FormatFlags::ALTERNATE_FORM) ==
203 FormatFlags::ALTERNATE_FORM);
204 constexpr char HEXADECIMAL_POINT = '.';
205
206 // This is for the letter 'p' before the exponent.
207 const char exp_seperator = a + ('p' - 'a');
208 constexpr int EXP_SEPERATOR_LEN = 1;
209
210 padding = to_conv.min_width - (sign_char > 0 ? 1 : 0) - PREFIX_LEN -
211 mant_digits - (has_hexadecimal_point ? 1 : 0) - EXP_SEPERATOR_LEN -
212 (EXP_LEN - exp_cur);
213 if (padding < 0)
214 padding = 0;
215
216 if ((to_conv.flags & FormatFlags::LEFT_JUSTIFIED) ==
217 FormatFlags::LEFT_JUSTIFIED) {
218 // The pattern is (sign), 0x, digit, (.), (other digits), (zeroes), p,
219 // exponent, (spaces)
220 if (sign_char > 0)
221 RET_IF_RESULT_NEGATIVE(writer->write(&sign_char, 1));
222 RET_IF_RESULT_NEGATIVE(writer->write(prefix, PREFIX_LEN));
223 RET_IF_RESULT_NEGATIVE(writer->write(mant_buffer, 1));
224 if (has_hexadecimal_point)
225 RET_IF_RESULT_NEGATIVE(writer->write(&HEXADECIMAL_POINT, 1));
226 if (mant_digits > 1)
227 RET_IF_RESULT_NEGATIVE(writer->write(mant_buffer + 1, mant_digits - 1));
228 if (trailing_zeroes > 0)
229 RET_IF_RESULT_NEGATIVE(writer->write_chars('0', trailing_zeroes));
230 RET_IF_RESULT_NEGATIVE(writer->write(&exp_seperator, EXP_SEPERATOR_LEN));
231 RET_IF_RESULT_NEGATIVE(
232 writer->write(exp_buffer + exp_cur, EXP_LEN - exp_cur));
233 if (padding > 0)
234 RET_IF_RESULT_NEGATIVE(writer->write_chars(' ', padding));
235 } else {
236 // The pattern is (spaces), (sign), 0x, (zeroes), digit, (.), (other
237 // digits), (zeroes), p, exponent
238 if ((padding > 0) && ((to_conv.flags & FormatFlags::LEADING_ZEROES) !=
239 FormatFlags::LEADING_ZEROES))
240 RET_IF_RESULT_NEGATIVE(writer->write_chars(' ', padding));
241 if (sign_char > 0)
242 RET_IF_RESULT_NEGATIVE(writer->write(&sign_char, 1));
243 RET_IF_RESULT_NEGATIVE(writer->write(prefix, PREFIX_LEN));
244 if ((padding > 0) && ((to_conv.flags & FormatFlags::LEADING_ZEROES) ==
245 FormatFlags::LEADING_ZEROES))
246 RET_IF_RESULT_NEGATIVE(writer->write_chars('0', padding));
247 RET_IF_RESULT_NEGATIVE(writer->write(mant_buffer, 1));
248 if (has_hexadecimal_point)
249 RET_IF_RESULT_NEGATIVE(writer->write(&HEXADECIMAL_POINT, 1));
250 if (mant_digits > 1)
251 RET_IF_RESULT_NEGATIVE(writer->write(mant_buffer + 1, mant_digits - 1));
252 if (trailing_zeroes > 0)
253 RET_IF_RESULT_NEGATIVE(writer->write_chars('0', trailing_zeroes));
254 RET_IF_RESULT_NEGATIVE(writer->write(&exp_seperator, EXP_SEPERATOR_LEN));
255 RET_IF_RESULT_NEGATIVE(
256 writer->write(exp_buffer + exp_cur, EXP_LEN - exp_cur));
257 }
258 return WRITE_OK;
259 }
260
261 } // namespace printf_core
262 } // namespace __llvm_libc
263
264 #endif // LLVM_LIBC_SRC_STDIO_PRINTF_CORE_FLOAT_HEX_CONVERTER_H
265