| //===-- Fixed Point Converter for printf ------------------------*- C++ -*-===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef LLVM_LIBC_SRC_STDIO_PRINTF_CORE_FIXED_CONVERTER_H |
| #define LLVM_LIBC_SRC_STDIO_PRINTF_CORE_FIXED_CONVERTER_H |
| |
| #include "include/llvm-libc-macros/stdfix-macros.h" |
| #include "src/__support/CPP/string_view.h" |
| #include "src/__support/fixed_point/fx_bits.h" |
| #include "src/__support/fixed_point/fx_rep.h" |
| #include "src/__support/integer_to_string.h" |
| #include "src/__support/libc_assert.h" |
| #include "src/stdio/printf_core/converter_utils.h" |
| #include "src/stdio/printf_core/core_structs.h" |
| #include "src/stdio/printf_core/writer.h" |
| |
| #include <inttypes.h> |
| #include <stddef.h> |
| |
| namespace LIBC_NAMESPACE { |
| namespace printf_core { |
| |
| // This is just for assertions. It will be compiled out for release builds. |
| LIBC_INLINE constexpr uint32_t const_ten_exp(uint32_t exponent) { |
| uint32_t result = 1; |
| LIBC_ASSERT(exponent < 11); |
| for (uint32_t i = 0; i < exponent; ++i) |
| result *= 10; |
| |
| return result; |
| } |
| |
| #define READ_FX_BITS(TYPE) \ |
| do { \ |
| auto fixed_bits = fixed_point::FXBits<TYPE>( \ |
| fixed_point::FXRep<TYPE>::StorageType(to_conv.conv_val_raw)); \ |
| integral = fixed_bits.get_integral(); \ |
| fractional = fixed_bits.get_fraction(); \ |
| exponent = fixed_bits.get_exponent(); \ |
| is_negative = fixed_bits.get_sign(); \ |
| } while (false) |
| |
| #define APPLY_FX_LENGTH_MODIFIER(LENGTH_MODIFIER) \ |
| do { \ |
| if (to_conv.conv_name == 'r') { \ |
| READ_FX_BITS(LENGTH_MODIFIER fract); \ |
| } else if (to_conv.conv_name == 'R') { \ |
| READ_FX_BITS(unsigned LENGTH_MODIFIER fract); \ |
| } else if (to_conv.conv_name == 'k') { \ |
| READ_FX_BITS(LENGTH_MODIFIER accum); \ |
| } else if (to_conv.conv_name == 'K') { \ |
| READ_FX_BITS(unsigned LENGTH_MODIFIER accum); \ |
| } else { \ |
| LIBC_ASSERT(false && "Invalid conversion name passed to convert_fixed"); \ |
| return FIXED_POINT_CONVERSION_ERROR; \ |
| } \ |
| } while (false) |
| |
| LIBC_INLINE int convert_fixed(Writer *writer, const FormatSection &to_conv) { |
| // Long accum should be the largest type, so we can store all the smaller |
| // numbers in things sized for it. |
| using LARep = fixed_point::FXRep<unsigned long accum>; |
| using StorageType = LARep::StorageType; |
| |
| // All of the letters will be defined relative to variable a, which will be |
| // the appropriate case based on the name of the conversion. This converts any |
| // conversion name into the letter 'a' with the appropriate case. |
| const char a = (to_conv.conv_name & 32) | 'A'; |
| FormatFlags flags = to_conv.flags; |
| |
| bool is_negative; |
| int exponent; |
| StorageType integral; |
| StorageType fractional; |
| |
| // r = fract |
| // k = accum |
| // lowercase = signed |
| // uppercase = unsigned |
| // h = short |
| // l = long |
| // any other length modifier has no effect |
| |
| if (to_conv.length_modifier == LengthModifier::h) { |
| APPLY_FX_LENGTH_MODIFIER(short); |
| } else if (to_conv.length_modifier == LengthModifier::l) { |
| APPLY_FX_LENGTH_MODIFIER(long); |
| } else { |
| APPLY_FX_LENGTH_MODIFIER(); |
| } |
| |
| LIBC_ASSERT(static_cast<size_t>(exponent) <= |
| (sizeof(StorageType) - sizeof(uint32_t)) * CHAR_BIT && |
| "StorageType must be large enough to hold the fractional " |
| "component multiplied by a 32 bit number."); |
| |
| // If to_conv doesn't specify a precision, the precision defaults to 6. |
| const size_t precision = to_conv.precision < 0 ? 6 : to_conv.precision; |
| bool has_decimal_point = |
| (precision > 0) || ((flags & FormatFlags::ALTERNATE_FORM) != 0); |
| |
| // The number of non-zero digits below the decimal point for a negative power |
| // of 2 in base 10 is equal to the magnitude of the power of 2. |
| |
| // A quick proof: |
| // Let p be any positive integer. |
| // Let e = 2^(-p) |
| // Let t be a positive integer such that e * 10^t is an integer. |
| // By definition: The smallest allowed value of t must be equal to the number |
| // of non-zero digits below the decimal point in e. |
| // If we evaluate e * 10^t we get the following: |
| // e * 10^t = 2^(-p) * 10*t = 2^(-p) * 2^t * 5^t = 5^t * 2^(t-p) |
| // For 5^t * 2^(t-p) to be an integer, both exponents must be non-negative, |
| // since 5 and 2 are coprime. |
| // The smallest value of t such that t-p is non-negative is p. |
| // Therefor, the number of non-zero digits below the decimal point for a given |
| // negative power of 2 "p" is equal to the value of p. |
| |
| constexpr size_t MAX_FRACTION_DIGITS = LARep::FRACTION_LEN; |
| |
| char fraction_digits[MAX_FRACTION_DIGITS]; |
| |
| size_t valid_fraction_digits = 0; |
| |
| // TODO: Factor this part out |
| while (fractional > 0) { |
| uint32_t cur_digits = 0; |
| // 10^9 is used since it's the largest power of 10 that fits in a uint32_t |
| constexpr uint32_t TEN_EXP_NINE = 1000000000; |
| constexpr size_t DIGITS_PER_BLOCK = 9; |
| |
| // Multiply by 10^9, then grab the digits above the decimal point, then |
| // clear those digits in fractional. |
| fractional = fractional * TEN_EXP_NINE; |
| cur_digits = static_cast<uint32_t>(fractional >> exponent); |
| fractional = fractional % (StorageType(1) << exponent); |
| |
| // we add TEN_EXP_NINE to force leading zeroes to show up, then we skip the |
| // first digit in the loop. |
| const IntegerToString<uint32_t> cur_fractional_digits(cur_digits + |
| TEN_EXP_NINE); |
| for (size_t i = 0; |
| i < DIGITS_PER_BLOCK && valid_fraction_digits < MAX_FRACTION_DIGITS; |
| ++i, ++valid_fraction_digits) |
| fraction_digits[valid_fraction_digits] = |
| cur_fractional_digits.view()[i + 1]; |
| |
| if (valid_fraction_digits >= MAX_FRACTION_DIGITS) { |
| LIBC_ASSERT(fractional == 0 && "If the fraction digit buffer is full, " |
| "there should be no remaining digits."); |
| /* |
| A visual explanation of what this assert is checking: |
| |
| 32 digits (max for 32 bit fract) |
| +------------------------------++--+--- must be zero |
| | || | |
| 123456789012345678901234567890120000 |
| | || || || | |
| +-------++-------++-------++-------+ |
| 9 digit blocks |
| */ |
| LIBC_ASSERT(cur_digits % const_ten_exp( |
| DIGITS_PER_BLOCK - |
| (MAX_FRACTION_DIGITS % DIGITS_PER_BLOCK)) == |
| 0 && |
| "Digits after the MAX_FRACTION_DIGITS should all be zero."); |
| valid_fraction_digits = MAX_FRACTION_DIGITS; |
| } |
| } |
| |
| if (precision < valid_fraction_digits) { |
| // Handle rounding. Just do round to nearest, tie to even since it's |
| // unspecified. |
| RoundDirection round; |
| char first_digit_after = fraction_digits[precision]; |
| if (first_digit_after > '5') { |
| round = RoundDirection::Up; |
| } else if (first_digit_after < '5') { |
| round = RoundDirection::Down; |
| } else { |
| // first_digit_after == '5' |
| // need to check the remaining digits, but default to even. |
| round = RoundDirection::Even; |
| for (size_t cur_digit_index = precision + 1; |
| cur_digit_index + 1 < valid_fraction_digits; ++cur_digit_index) { |
| if (fraction_digits[cur_digit_index] != '0') { |
| round = RoundDirection::Up; |
| break; |
| } |
| } |
| } |
| |
| // If we need to actually perform rounding, do so. |
| if (round == RoundDirection::Up || round == RoundDirection::Even) { |
| bool keep_rounding = true; |
| int digit_to_round = static_cast<int>(precision) - 1; |
| for (; digit_to_round >= 0 && keep_rounding; --digit_to_round) { |
| keep_rounding = false; |
| char cur_digit = fraction_digits[digit_to_round]; |
| // if the digit should not be rounded up |
| if (round == RoundDirection::Even && ((cur_digit - '0') % 2) == 0) { |
| // break out of the loop |
| break; |
| } |
| fraction_digits[digit_to_round] += 1; |
| |
| // if the digit was a 9, instead replace with a 0. |
| if (cur_digit == '9') { |
| fraction_digits[digit_to_round] = '0'; |
| keep_rounding = true; |
| } |
| } |
| |
| // if every digit below the decimal point was rounded up but we need to |
| // keep rounding |
| if (keep_rounding && |
| (round == RoundDirection::Up || |
| (round == RoundDirection::Even && ((integral % 2) == 1)))) { |
| // add one to the integral portion to round it up. |
| ++integral; |
| } |
| } |
| |
| valid_fraction_digits = precision; |
| } |
| |
| const IntegerToString<StorageType> integral_str(integral); |
| |
| // these are signed to prevent underflow due to negative values. The |
| // eventual values will always be non-negative. |
| size_t trailing_zeroes = 0; |
| int padding; |
| |
| // If the precision is greater than the actual result, pad with 0s |
| if (precision > valid_fraction_digits) |
| trailing_zeroes = precision - (valid_fraction_digits); |
| |
| constexpr cpp::string_view DECIMAL_POINT("."); |
| |
| char sign_char = 0; |
| |
| // Check if the conv name is uppercase |
| if (a == 'A') { |
| // These flags are only for signed conversions, so this removes them if the |
| // conversion is unsigned. |
| flags = FormatFlags(flags & |
| ~(FormatFlags::FORCE_SIGN | FormatFlags::SPACE_PREFIX)); |
| } |
| |
| if (is_negative) |
| sign_char = '-'; |
| else if ((flags & FormatFlags::FORCE_SIGN) == FormatFlags::FORCE_SIGN) |
| sign_char = '+'; // FORCE_SIGN has precedence over SPACE_PREFIX |
| else if ((flags & FormatFlags::SPACE_PREFIX) == FormatFlags::SPACE_PREFIX) |
| sign_char = ' '; |
| |
| padding = static_cast<int>(to_conv.min_width - (sign_char > 0 ? 1 : 0) - |
| integral_str.size() - |
| static_cast<int>(has_decimal_point) - |
| valid_fraction_digits - trailing_zeroes); |
| if (padding < 0) |
| padding = 0; |
| |
| if ((flags & FormatFlags::LEFT_JUSTIFIED) == FormatFlags::LEFT_JUSTIFIED) { |
| // The pattern is (sign), integral, (.), (fraction), (zeroes), (spaces) |
| if (sign_char > 0) |
| RET_IF_RESULT_NEGATIVE(writer->write(sign_char)); |
| RET_IF_RESULT_NEGATIVE(writer->write(integral_str.view())); |
| if (has_decimal_point) |
| RET_IF_RESULT_NEGATIVE(writer->write(DECIMAL_POINT)); |
| if (valid_fraction_digits > 0) |
| RET_IF_RESULT_NEGATIVE( |
| writer->write({fraction_digits, valid_fraction_digits})); |
| if (trailing_zeroes > 0) |
| RET_IF_RESULT_NEGATIVE(writer->write('0', trailing_zeroes)); |
| if (padding > 0) |
| RET_IF_RESULT_NEGATIVE(writer->write(' ', padding)); |
| } else { |
| // The pattern is (spaces), (sign), (zeroes), integral, (.), (fraction), |
| // (zeroes) |
| if ((padding > 0) && |
| ((flags & FormatFlags::LEADING_ZEROES) != FormatFlags::LEADING_ZEROES)) |
| RET_IF_RESULT_NEGATIVE(writer->write(' ', padding)); |
| if (sign_char > 0) |
| RET_IF_RESULT_NEGATIVE(writer->write(sign_char)); |
| if ((padding > 0) && |
| ((flags & FormatFlags::LEADING_ZEROES) == FormatFlags::LEADING_ZEROES)) |
| RET_IF_RESULT_NEGATIVE(writer->write('0', padding)); |
| RET_IF_RESULT_NEGATIVE(writer->write(integral_str.view())); |
| if (has_decimal_point) |
| RET_IF_RESULT_NEGATIVE(writer->write(DECIMAL_POINT)); |
| if (valid_fraction_digits > 0) |
| RET_IF_RESULT_NEGATIVE( |
| writer->write({fraction_digits, valid_fraction_digits})); |
| if (trailing_zeroes > 0) |
| RET_IF_RESULT_NEGATIVE(writer->write('0', trailing_zeroes)); |
| } |
| return WRITE_OK; |
| } |
| |
| } // namespace printf_core |
| } // namespace LIBC_NAMESPACE |
| |
| #endif // LLVM_LIBC_SRC_STDIO_PRINTF_CORE_FIXED_CONVERTER_H |