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