[libc] [llvm] [libc] Add fixed point support to printf (PR #82707)

Michael Jones via llvm-commits llvm-commits at lists.llvm.org
Mon Feb 26 14:37:26 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();
+    }
+  }
----------------
michaelrj-google wrote:

That doesn't solve my problem, we'd still need this terrible nested set of `if`s.

https://github.com/llvm/llvm-project/pull/82707


More information about the llvm-commits mailing list