[libc] [llvm] [libc] Add fixed point support to printf (PR #82707)
Nick Desaulniers via llvm-commits
llvm-commits at lists.llvm.org
Mon Feb 26 10:28:24 PST 2024
================
@@ -0,0 +1,386 @@
+//===-- 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 (size_t i = 0; i < exponent; ++i)
+ result *= 10;
+
+ return result;
+}
+
+LIBC_INLINE int convert_fixed(Writer *writer, const FormatSection &to_conv) {
+ using SAStorageType = fixed_point::FXRep<short accum>::StorageType;
+ using AStorageType = fixed_point::FXRep<accum>::StorageType;
+ using LAStorageType = fixed_point::FXRep<long accum>::StorageType;
+ using SFStorageType = fixed_point::FXRep<short fract>::StorageType;
+ using FStorageType = fixed_point::FXRep<fract>::StorageType;
+ using LFStorageType = fixed_point::FXRep<long fract>::StorageType;
+
+ // 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;
+
+ // TODO: See about simplifying this mess of a 3D matrix if statement.
+ // 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) {
+ // short types
+ if (to_conv.conv_name == 'r') {
+ auto fixed_bits = fixed_point::FXBits<short fract>(
+ static_cast<SFStorageType>(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();
+ }
+ if (to_conv.conv_name == 'R') {
+ auto fixed_bits = fixed_point::FXBits<unsigned short fract>(
+ static_cast<SFStorageType>(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();
+ }
+ if (to_conv.conv_name == 'k') {
+ auto fixed_bits = fixed_point::FXBits<short accum>(
+ static_cast<SAStorageType>(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();
+ }
+ if (to_conv.conv_name == 'K') {
+ auto fixed_bits = fixed_point::FXBits<unsigned short accum>(
+ static_cast<SAStorageType>(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();
+ }
+ } else if (to_conv.length_modifier == LengthModifier::l) {
+ // long types
+ if (to_conv.conv_name == 'r') {
+ auto fixed_bits = fixed_point::FXBits<long fract>(
+ static_cast<LFStorageType>(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();
+ }
+ if (to_conv.conv_name == 'R') {
+ auto fixed_bits = fixed_point::FXBits<unsigned long fract>(
+ static_cast<LFStorageType>(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();
+ }
+ if (to_conv.conv_name == 'k') {
+ auto fixed_bits = fixed_point::FXBits<long accum>(
+ static_cast<LAStorageType>(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();
+ }
+ if (to_conv.conv_name == 'K') {
+ auto fixed_bits = fixed_point::FXBits<unsigned long accum>(
+ static_cast<LAStorageType>(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();
+ }
+ } else {
+ // unspecified types
+ if (to_conv.conv_name == 'r') {
+ auto fixed_bits = fixed_point::FXBits<fract>(
+ static_cast<FStorageType>(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();
+ }
+ if (to_conv.conv_name == 'R') {
+ auto fixed_bits = fixed_point::FXBits<unsigned fract>(
+ static_cast<FStorageType>(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();
+ }
+ if (to_conv.conv_name == 'k') {
+ auto fixed_bits = fixed_point::FXBits<accum>(
+ static_cast<AStorageType>(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();
+ }
+ if (to_conv.conv_name == 'K') {
+ auto fixed_bits = fixed_point::FXBits<unsigned accum>(
+ static_cast<AStorageType>(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();
+ }
+ }
+
+ 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.");
+
+ 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 = ' ';
----------------
nickdesaulniers wrote:
`sign_char` isn't used until a bit later. Can you move this block down closer to where it's first used?
https://github.com/llvm/llvm-project/pull/82707
More information about the llvm-commits
mailing list