[llvm] [APFloat] Add APFloat::format (PR #99088)

via llvm-commits llvm-commits at lists.llvm.org
Tue Jul 16 14:09:21 PDT 2024


https://github.com/Ariel-Burton updated https://github.com/llvm/llvm-project/pull/99088

>From af2f1f060e642737fc5607c5e80fa6b8d8f83b53 Mon Sep 17 00:00:00 2001
From: Ariel Burton <ariel.burton at ibm.com>
Date: Tue, 16 Jul 2024 18:50:25 +0000
Subject: [PATCH 1/2] [APFloat] Add APFloat::format

This PR adds the format method to the APFloat family.
This is intended to ease formatting of an APFloat to a
string without having to convert the APFloat to a host-format
floating point value.
This is useful when the target type cannot be losslessly
converted to a host type.
---
 llvm/include/llvm/ADT/APFloat.h    |  25 ++
 llvm/lib/Support/APFloat.cpp       | 361 +++++++++++++++++++++++++++++
 llvm/unittests/ADT/APFloatTest.cpp | 156 +++++++++++++
 3 files changed, 542 insertions(+)

diff --git a/llvm/include/llvm/ADT/APFloat.h b/llvm/include/llvm/ADT/APFloat.h
index db2fa480655c6..f2ed3a5d22b82 100644
--- a/llvm/include/llvm/ADT/APFloat.h
+++ b/llvm/include/llvm/ADT/APFloat.h
@@ -15,10 +15,12 @@
 #ifndef LLVM_ADT_APFLOAT_H
 #define LLVM_ADT_APFLOAT_H
 
+#include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/APInt.h"
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/FloatingPointMode.h"
 #include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/NativeFormatting.h"
 #include "llvm/Support/float128.h"
 #include <memory>
 
@@ -557,6 +559,14 @@ class IEEEFloat final : public APFloatBase {
 
   cmpResult compareAbsoluteValue(const IEEEFloat &) const;
 
+  /// returns the exponent in the format's radix
+  ExponentType getExponent() const;
+
+  /// returns the significand
+  APInt getSignificand() const;
+
+  /// decompose to an integer and exponent to radix 2
+  bool decomposeToIntegerAndPowerOf2(APInt &, int &) const;
 private:
   /// \name Simple Queries
   /// @{
@@ -784,6 +794,8 @@ class DoubleAPFloat final : public APFloatBase {
 
   bool getExactInverse(APFloat *inv) const;
 
+  bool decomposeToIntegerAndPowerOf2(APInt &, int &) const;
+
   LLVM_READONLY
   int getExactLog2() const;
   LLVM_READONLY
@@ -1381,6 +1393,19 @@ class APFloat : public APFloatBase {
         toString(Str, FormatPrecision, FormatMaxPadding, TruncateZero));
   }
 
+  /// Decomposes the value to an integer and an exponent such that
+  /// value = I * 2^exp
+  /// returns true on success, false otherwise (e.g., NaN, Infinity)
+  /// similar to the standard modf, but exponent does not
+  /// have to have the same sign as the value.
+  bool decomposeToIntegerAndPowerOf2 (APInt &I, int &exp) const {
+    APFLOAT_DISPATCH_ON_SEMANTICS( decomposeToIntegerAndPowerOf2(I, exp));
+  }
+
+  SmallVectorImpl<char> &format(SmallVectorImpl<char> &strout,
+              llvm::FloatStyle style = llvm::FloatStyle::Exponent,
+              std::optional<size_t> precision = std::nullopt);
+
   void print(raw_ostream &) const;
   void dump() const;
 
diff --git a/llvm/lib/Support/APFloat.cpp b/llvm/lib/Support/APFloat.cpp
index 3664de71d06df..cf9793d6e3f76 100644
--- a/llvm/lib/Support/APFloat.cpp
+++ b/llvm/lib/Support/APFloat.cpp
@@ -4596,6 +4596,39 @@ void IEEEFloat::makeZero(bool Negative) {
   APInt::tcSet(significandParts(), 0, partCount());
 }
 
+IEEEFloat::ExponentType IEEEFloat::getExponent() const {
+  return exponent;
+}
+
+APInt IEEEFloat::getSignificand() const {
+  APInt result(semantics->precision, ArrayRef<integerPart>(significandParts(), partCount()));
+
+  return result;
+}
+
+bool IEEEFloat::decomposeToIntegerAndPowerOf2(APInt &I, int &exp) const {
+  if (isNaN() || isInfinity())
+    return false;
+
+  if (isZero()) {
+    I = APInt(semantics->precision, 0);
+    exp = 0;
+  } else {
+    // the significant bits are the significand
+    I = getSignificand();
+    // now set up the exp.
+    // In IEEEFloat the radix point is immediately to the right
+    // of the left most bit, i.e., the significand is s.ssssss... .
+    exp = exponent - (semantics->precision - 1);
+
+    // get rid of any trailing zeros
+    int nTrailingZeros = I.countr_zero();
+    exp += nTrailingZeros;
+    I.lshrInPlace(nTrailingZeros);
+  }
+  return true;
+}
+
 void IEEEFloat::makeQuiet() {
   assert(isNaN());
   if (semantics->nonFiniteBehavior != fltNonfiniteBehavior::NanOnly)
@@ -5217,6 +5250,50 @@ bool DoubleAPFloat::getExactInverse(APFloat *inv) const {
   return Ret;
 }
 
+bool DoubleAPFloat::decomposeToIntegerAndPowerOf2(APInt &I, int &exp) const {
+  APInt a, b;
+  int aExp, bExp;
+  bool aOK = Floats[0].decomposeToIntegerAndPowerOf2(a, aExp);
+  bool bOK = Floats[1].decomposeToIntegerAndPowerOf2(b, bExp);
+
+  if (aOK && bOK) {
+    if (aExp > bExp) {
+      int deltaExp = aExp - bExp;
+      // shift a left to reduce its exponent to be the same as b
+      a = a.zext(a.getBitWidth() + deltaExp);
+      a <<= deltaExp;
+      exp = bExp;
+    } else if (bExp > aExp) {
+      int deltaExp = bExp - aExp;
+      // shift b left to reduce its exponent to be the same as a
+      b = b.zext(b.getBitWidth() + deltaExp);
+      b <<= deltaExp;
+      exp = aExp;
+    } else {
+      exp = aExp;
+    }
+    // now do the addition
+
+    // need to extend the operands to be the same length,
+    // and allow a bit for a possible carry (hence the +1).
+    // Note: the +1 means that the new length is greater
+    //       than the lengths of both a and b.
+    //       That means that we can use zext safely.
+    int bw = 1 + std::max(a.getBitWidth(), b.getBitWidth());
+    a = a.zext(bw);
+    b = b.zext(bw);
+    I = a + b;
+
+    // now check for trailing zeros
+    int nTrailingZeros = I.countr_zero();
+    exp += nTrailingZeros;
+    I.lshrInPlace(nTrailingZeros);
+
+    return true;
+  }
+  return false;
+}
+
 int DoubleAPFloat::getExactLog2() const {
   // TODO: Implement me
   return INT_MIN;
@@ -5323,6 +5400,290 @@ APFloat APFloat::getAllOnesValue(const fltSemantics &Semantics) {
   return APFloat(Semantics, APInt::getAllOnes(Semantics.sizeInBits));
 }
 
+SmallVectorImpl<char> &APFloat::format(SmallVectorImpl<char> &strout,
+                                     llvm::FloatStyle style,
+                                     std::optional<size_t> precision_in) {
+  size_t precision = precision_in.value_or(getDefaultPrecision(style));
+
+  // everything that follows assumes that precision >= 0
+  assert(precision >= 0);
+
+  // deal with the special cases
+  if (isNaN()) {
+    detail::append(strout, "nan");
+    return strout;
+  } else if (isInfinity()) {
+    if (isNegative())
+      detail::append(strout, "-INF");
+    else
+      detail::append(strout, "INF");
+    return strout;
+  } else if (isZero()) {
+    if (isNegative())
+      strout.push_back('-');
+    strout.push_back('0');
+    if (precision > 0) {
+      strout.push_back('.');
+      for (size_t i = 0; i < precision; ++i)
+        strout.push_back('0');
+    }  
+    if (style == FloatStyle::Exponent)
+      detail::append(strout, "e+00");
+    else if (style == FloatStyle::ExponentUpper)
+      detail::append(strout, "E+00");
+    else if (style == FloatStyle::Percent)
+      strout.push_back('%');
+    return strout;
+  }
+
+  // check we've dealt with all the special cases
+  assert(!isNaN() && !isInfinity() && !isZero());
+
+  // get as an integer and radix 2 exponent
+  APInt I;
+  int E;
+  decomposeToIntegerAndPowerOf2(I, E);
+
+  // convert from base 2 to base 10
+  if (0 == E) {
+    // then nothing to do --- s is an integer
+  } else if (E > 0) {
+    // shift left and reduce e to 0
+    int numLeadingZeros = I.countl_zero();
+    if (E > numLeadingZeros)
+      I = I.zext(I.getBitWidth() + E - numLeadingZeros);
+    I <<= E;
+    E = 0;
+  } else {
+    // we want to convert a negative base 2 exponent
+    // to a negative base 10 exponent:
+    //   I * 2^-E   = I * 2^-E * 5^E * 5^-E
+    //              = I * 5^E * 2^-E * 5^-E
+    //              = (I * 5^E) * (2*5)^-E
+    //              = (I * 5^E) * 10^-E
+    // that is, we need to multiply I by 5^-exp and treat
+    // the exponent as being base 10
+
+    // 5^13 = 5^(8+4+1)
+    //
+    // Now work our how many bits we need for the product I * 5^E
+    // We need log2(I * 5^E)  = log2(s) + log2(5^E)
+    //                        = log2(s) + e * log2(5)
+    // log2(5) ~ 2.321928096 < 2.322033898 ~ 137/59
+    // log2(I) <= I.getBitWidth()
+
+    I = I.zext(I.getBitWidth() + (137 * -E + 136) / 59);
+    APInt power5(I.getBitWidth(), 5);
+    int exp = -E;
+    assert(exp > 0);
+    for (;;) {
+      if (exp & 1)
+        I *= power5;
+      exp >>= 1;
+      if (0 == exp)
+        break;
+      power5 *= power5;
+    }
+  }
+
+  // at this point s is an intger, and exp is either 0, or is negative
+  assert(E <= 0);
+
+  // convert s to a string
+  SmallVector<char> s;
+  I.toString(s, 10, false);
+
+  // The decimal point is at position -E (recall E is <= 0)
+  // relative to the END of the string.  If E == 0, the decimal
+  // point is to the right of the last position.
+  // Thus, if decimalPoint == s.size() + E, the decimal point is
+  // immediately to the left of s[decimalPoint].
+  // If decimalPoint is 0, the decimal point is immediately
+  // before the start of s.  If it is negative, then there are
+  // implicit zeros to the left of s.
+  int decimalPoint = s.size() + E;
+  E = 0;
+
+  if (style == FloatStyle::Exponent || style == FloatStyle::ExponentUpper) {
+    // this corresponds to printf("%e"), or [-]d[.dd..dd]e(+|-)dd
+    // We need one digit to the left of the decimal point.
+    // In other words, we need to make decimalPoint 1,
+    // and adjust E.
+    E = decimalPoint - 1;
+    decimalPoint = 1;
+
+    // now need to deal with the precision.
+    if (precision < (s.size() - 1) && (s[precision + 1] >= '5')) {
+      // then need to round.  What we do is extract the
+      // the first (precision + 1) digits from s (precision
+      // digits after the decimal point, and one for the
+      // the single dight to the left of the decimal point).
+      // We know that because the next position is at least 5
+      // that the left most place of the digits retain would
+      // be retained.
+      // What we need to do is increment what's left.
+
+      int nDigits = precision + 1;
+      StringRef significantDigits(s.data(), nDigits);
+      // temporarily move the decimal place to the end
+      // We do this to handle the case when the single
+      // digit to the left of the decimal point is 9,
+      // and it rolls over to 10.
+      E -= (nDigits - 1);
+
+      APInt temp(I.getBitWidth(), significantDigits, 10);
+      temp += 1;
+      s.clear();
+      temp.toString(s, 10, false);
+
+      // now move decimal point back
+      E += (s.size() - 1);
+    }
+    if(isNegative())
+      strout.push_back('-');
+    strout.push_back(s[0]);
+    if (precision > 0) {
+      strout.push_back('.');
+      if (precision > (s.size() - 1)) {
+        // then need to print all the digits we have,
+        // and possibly some trailing zeros
+        detail::append(strout, StringRef(s.data() + 1, s.size() - 1));
+        for (auto i = s.size() - 1; i < precision; i++)
+          strout.push_back('0');
+      } else {
+        // need only some of the digits
+        StringRef restOfDigits(s.data() + 1, precision);
+        detail::append(strout, restOfDigits);
+      }
+    }
+    if (style == FloatStyle::Exponent)
+      strout.push_back('e');
+    else
+      strout.push_back('E');
+    if (E < 0) {
+      strout.push_back('-');
+      E = -E;
+    } else {
+      strout.push_back('+');
+    }
+    // need a minimum of two digits for the exponent
+    if (E < 10) {
+      strout.push_back('0');
+      strout.push_back('0' + E);
+    } else {
+      s.clear();
+      while(E) {
+        char c = '0' + E % 10;
+        strout.push_back(c);
+        E /= 10;
+      }
+      std::reverse(s.begin(), s.end());
+      detail::append(strout, StringRef(s.data(), s.size()));
+    }
+    return strout;
+  }
+
+  // output to be formatted along the lines of %f
+  if (style == FloatStyle::Percent)
+    decimalPoint += 2;    // multiply by 100
+
+  int decidingDigit = decimalPoint + precision;
+
+  if (decidingDigit < 0) {
+    // theh value is zero.  The deciding digit is to the left
+    // of the digits in s.  This is in the area of zeros, and
+    // the contents of s can't affect the value.
+  } else if (decidingDigit >= (int) s.size()) {
+    // deciding is beyond the end of s
+  } else if (decidingDigit == 0) {
+    // this is a tricky case, because if the digit at position 0
+    // is >= 5, then the digit to the left, which is an implicit
+    // 0 that is not represented, needs to be incremented.
+    if (s[0] >= '5') {
+      // then need to carry.
+      // What we do is clear s, and insert a '1' at the start of s
+      // (note it must be 1), and increment decimalPoint.
+      // We don't need the rest of the digits because they
+      // don't contribute to the value to be displayed.
+      s.clear();
+      s.push_back('1');
+      decimalPoint++;
+    }
+  } else if (s[decidingDigit] >= '5') {
+    StringRef significantDigits(s.data(), decidingDigit);
+    int distanceBetweenDecimalPointAndDecidingDigit = decidingDigit - decimalPoint;
+    APInt temp (I.getBitWidth(), significantDigits, 10);
+    temp += 1;
+    s.clear();
+    temp.toString(s, 10, false);
+    // readjust decimalPoint in case the addition had a carry out
+    decimalPoint = (int) s.size() - distanceBetweenDecimalPointAndDecidingDigit;
+  }
+
+  if (isNegative())
+    strout.push_back('-');
+
+  // emit the integer part.  There will always be an integet:
+  // if there is a decimal point, then at least one digit
+  // must appear to its left.  If there is no decimal, then
+  // the value is displayed as an integer.
+  if (decimalPoint < 1) {
+    strout.push_back('0');
+  } else {
+    // we need to emit decimalPoint digits
+    int fromS = std::min(decimalPoint, (int) s.size());
+    int i;
+
+    for (i = 0; i < fromS; i++)
+      strout.push_back(s[i]);
+    for (; i < decimalPoint; i++)
+      strout.push_back('0');
+  }
+
+  if (precision > 0 ) {
+    // need to emit precision digits
+    // We need to emit what's to the right of the decimal point.
+    int i;
+    strout.push_back('.');
+    if (decimalPoint < 0) {
+      int numLeadingZeros = std::min((int) precision, -decimalPoint);
+      for (i = 0; i < numLeadingZeros; i++)
+        strout.push_back('0');
+      // update how many digits we have left to emit
+      precision -= numLeadingZeros;
+      // update where we need to emit them from
+      decimalPoint += numLeadingZeros;
+    }
+
+    if ( precision > 0) {
+      // decimalPoint must be >= 0.
+      // If it was < 0 befoew we emitted the integer to the left of the decimal ppint,
+      // then it would have been incremented by numLeadingZeros in the previous block.
+      // It would have been incremented by the smaller of |decimalPoint| and precision.
+      // if |decimalPoint| were smaller, then decimalPoint will now be 0.
+      // If precision were smaller, then precision would have been decremented to 0,
+      // so we wouldn't be in this block.
+      // Hencem if we are in this block, then decimalPoint must be >= 0.
+      assert(decimalPoint >= 0);
+      if (decimalPoint < (int) s.size()) {
+        // we need to emit digits from s
+        int fromS = std::min(precision, s.size() - decimalPoint);
+
+        for (i = 0; i < fromS; i++)
+          strout.push_back(s[decimalPoint + i]);
+        precision -= fromS;
+      }
+      for ( i = 0; i < (int) precision; i++ )
+        strout.push_back('0');
+    }
+  }
+
+  if (style == FloatStyle::Percent)
+    strout.push_back('%');
+
+  return strout;
+}
+
 void APFloat::print(raw_ostream &OS) const {
   SmallVector<char, 16> Buffer;
   toString(Buffer);
diff --git a/llvm/unittests/ADT/APFloatTest.cpp b/llvm/unittests/ADT/APFloatTest.cpp
index 86a25f4394e19..a718c49dc662e 100644
--- a/llvm/unittests/ADT/APFloatTest.cpp
+++ b/llvm/unittests/ADT/APFloatTest.cpp
@@ -1378,6 +1378,162 @@ TEST(APFloatTest, toString) {
   }
 }
 
+TEST(APFloatTest, format) {
+  auto doit_precision = [](const fltSemantics &S, const char *value, llvm::FloatStyle style, int precision, const char *expected) {
+
+    SmallString<16>  s;
+    APFloat apf(S, value);
+    apf.format(s, style, precision);
+    EXPECT_STREQ(expected, s.c_str());
+  };
+  auto doit = [](const fltSemantics &S, const char *value, llvm::FloatStyle style, const char *expected) {
+
+    SmallString<16>  s;
+    APFloat apf(S, value);
+    apf.format(s, style);
+    EXPECT_STREQ(expected, s.c_str());
+  };
+
+
+  // default precision for Exponent and ExponentUpper is 6
+  // and 2 for Fixed and Psercent
+  // All float formats should be able to handle small vlues.
+  // The smaller formats, like float8, are more restricted.
+  for (unsigned I = 0; I != APFloat::S_MaxSemantics + 1; ++I) {
+    auto SemEnum = static_cast<APFloat::Semantics>(I);
+    const auto &S = APFloat::EnumToSemantics(SemEnum);
+    auto Precision = APFloat::semanticsPrecision(S);
+
+    // check 0
+    doit(S, "0.0", llvm::FloatStyle::Exponent, "0.000000e+00");
+    doit(S, "0.0", llvm::FloatStyle::ExponentUpper, "0.000000E+00");
+    doit(S, "0.0", llvm::FloatStyle::Fixed, "0.00");
+    doit(S, "0.0", llvm::FloatStyle::Percent, "0.00%");
+
+    // check that Exponent shifts left
+    doit(S, "0.5", llvm::FloatStyle::Exponent, "5.000000e-01");
+    doit(S, "0.5", llvm::FloatStyle::ExponentUpper, "5.000000E-01");
+    doit(S, "0.5", llvm::FloatStyle::Fixed, "0.50");
+    doit(S, "0.5", llvm::FloatStyle::Percent, "50.00%");
+
+    // check 1
+    doit(S, "1.0", llvm::FloatStyle::Exponent, "1.000000e+00");
+    doit(S, "1.0", llvm::FloatStyle::ExponentUpper, "1.000000E+00");
+    doit(S, "1.0", llvm::FloatStyle::Fixed, "1.00");
+    doit(S, "1.0", llvm::FloatStyle::Percent, "100.00%");
+
+    // check something with both an integer and a fraction
+    doit(S, "1.5", llvm::FloatStyle::Exponent, "1.500000e+00");
+    doit(S, "1.5", llvm::FloatStyle::ExponentUpper, "1.500000E+00");
+    doit(S, "1.5", llvm::FloatStyle::Fixed, "1.50");
+    doit(S, "1.5", llvm::FloatStyle::Percent, "150.00%");
+
+    // check negative
+    doit(S, "-1.5", llvm::FloatStyle::Exponent, "-1.500000e+00");
+    doit(S, "-1.5", llvm::FloatStyle::ExponentUpper, "-1.500000E+00");
+    doit(S, "-1.5", llvm::FloatStyle::Fixed, "-1.50");
+    doit(S, "-1.5", llvm::FloatStyle::Percent, "-150.00%");
+
+
+    // check rounding: 0
+    doit_precision(S, "0.0", llvm::FloatStyle::Exponent, 0, "0e+00");
+    doit_precision(S, "0.0", llvm::FloatStyle::ExponentUpper, 0, "0E+00");
+    doit_precision(S, "0.0", llvm::FloatStyle::Fixed, 0, "0");
+    doit_precision(S, "0.0", llvm::FloatStyle::Percent, 0, "0%");
+
+    // check round down
+    if (Precision >= 3) {
+      doit_precision(S, "1.25", llvm::FloatStyle::Exponent, 0, "1e+00");
+      doit_precision(S, "1.25", llvm::FloatStyle::ExponentUpper, 0, "1E+00");
+      doit_precision(S, "1.25", llvm::FloatStyle::Fixed, 0, "1");
+      doit_precision(S, "1.25", llvm::FloatStyle::Percent, 0, "125%");
+    }
+
+    // check round up
+    if (Precision >= 3) {
+      doit_precision(S, "1.25", llvm::FloatStyle::Exponent, 1, "1.3e+00");
+      doit_precision(S, "1.25", llvm::FloatStyle::ExponentUpper, 1, "1.3E+00");
+      doit_precision(S, "1.25", llvm::FloatStyle::Fixed, 1, "1.3");
+      doit_precision(S, "1.25", llvm::FloatStyle::Percent, 1, "125.0%");
+    }
+
+    // check round up to integer
+    if (Precision >= 3) {
+      doit_precision(S, "1.75", llvm::FloatStyle::Exponent, 0, "2e+00");
+      doit_precision(S, "1.75", llvm::FloatStyle::ExponentUpper, 0, "2E+00");
+      doit_precision(S, "1.75", llvm::FloatStyle::Fixed, 0, "2");
+      doit_precision(S, "1.75", llvm::FloatStyle::Percent, 0, "175%");
+    }
+
+    // check round up
+    if (Precision >= 3) {
+      doit_precision(S, "1.75", llvm::FloatStyle::Exponent, 1, "1.8e+00");
+      doit_precision(S, "1.75", llvm::FloatStyle::ExponentUpper, 1, "1.8E+00");
+      doit_precision(S, "1.75", llvm::FloatStyle::Fixed, 1, "1.8");
+      doit_precision(S, "1.75", llvm::FloatStyle::Percent, 1, "175.0%");
+    }
+
+    // check appending fewer than default number of zeros
+    if (Precision >= 3) {
+      doit_precision(S, "1.75", llvm::FloatStyle::Exponent, 3, "1.750e+00");
+      doit_precision(S, "1.75", llvm::FloatStyle::ExponentUpper, 3, "1.750E+00");
+      doit_precision(S, "1.75", llvm::FloatStyle::Fixed, 3, "1.750");
+      doit_precision(S, "1.75", llvm::FloatStyle::Percent, 3, "175.000%");
+    }
+
+    // check appending more than default number of zeros
+    if (Precision >= 3) {
+      doit_precision(S, "1.75", llvm::FloatStyle::Exponent, 8, "1.75000000e+00");
+      doit_precision(S, "1.75", llvm::FloatStyle::ExponentUpper, 8, "1.75000000E+00");
+      doit_precision(S, "1.75", llvm::FloatStyle::Fixed, 8, "1.75000000");
+      doit_precision(S, "1.75", llvm::FloatStyle::Percent, 8, "175.00000000%");
+    }
+  }
+
+  // test the main types with wider ranges
+  auto sems = { llvm::APFloat::S_IEEEsingle, llvm::APFloat::S_IEEEdouble,
+                llvm::APFloat::S_IEEEquad, llvm::APFloat::S_PPCDoubleDouble,
+                llvm::APFloat::S_x87DoubleExtended};
+
+  for ( auto sem : sems ) {
+    const auto &S = APFloat::EnumToSemantics(sem);
+
+    doit(S, "0.000001", llvm::FloatStyle::Exponent, "1.000000e-06");
+    // check what happens if we have a value that ends in 0s in binary
+    doit(S, "1024.0", llvm::FloatStyle::ExponentUpper, "1.024000E+03");
+    doit(S, "1024.0", llvm::FloatStyle::Fixed, "1024.00");
+
+    // 1/1024 == 0.0009765625
+    doit(S, "0.0009765625", llvm::FloatStyle::Exponent, "9.765625e-04");
+    doit_precision(S, "0.0009765625", llvm::FloatStyle::Exponent, 5, "9.76563e-04");
+    doit_precision(S, "0.0009765625", llvm::FloatStyle::Exponent, 4, "9.7656e-04");
+    doit_precision(S, "0.0009765625", llvm::FloatStyle::Exponent, 3, "9.766e-04");
+    doit_precision(S, "0.0009765625", llvm::FloatStyle::Exponent, 2, "9.77e-04");
+    doit_precision(S, "0.0009765625", llvm::FloatStyle::Exponent, 1, "9.8e-04");
+    // note change in exponent as the integer 9 goes to 10, and then to 1
+    doit_precision(S, "0.0009765625", llvm::FloatStyle::Exponent, 0, "1e-03");
+
+    doit_precision(S, "0.0009765625", llvm::FloatStyle::Fixed, 11, "0.00097656250");
+    doit_precision(S, "0.0009765625", llvm::FloatStyle::Fixed, 10, "0.0009765625");
+    doit_precision(S, "0.0009765625", llvm::FloatStyle::Fixed, 9, "0.000976563");
+    doit_precision(S, "0.0009765625", llvm::FloatStyle::Fixed, 8, "0.00097656");
+    doit_precision(S, "0.0009765625", llvm::FloatStyle::Fixed, 7, "0.0009766");
+    doit_precision(S, "0.0009765625", llvm::FloatStyle::Fixed, 6, "0.000977");
+    doit_precision(S, "0.0009765625", llvm::FloatStyle::Fixed, 5, "0.00098");
+    doit_precision(S, "0.0009765625", llvm::FloatStyle::Fixed, 4, "0.0010");
+    doit_precision(S, "0.0009765625", llvm::FloatStyle::Fixed, 3, "0.001");
+    doit_precision(S, "0.0009765625", llvm::FloatStyle::Fixed, 2, "0.00");
+    doit_precision(S, "0.0009765625", llvm::FloatStyle::Fixed, 1, "0.0");
+    doit_precision(S, "0.0009765625", llvm::FloatStyle::Fixed, 0, "0");
+    doit(S, "0.0009765625", llvm::FloatStyle::Fixed, "0.00");
+
+    // these next two cases have the rounding deciding digit at the
+    // beginning of the internal string
+    doit_precision(S, "0.03125", llvm::FloatStyle::Fixed, 1, "0.0"); // 1/32
+    doit_precision(S, "0.0625", llvm::FloatStyle::Fixed, 1, "0.1");  // 1/16
+  }
+}
+
 TEST(APFloatTest, toInteger) {
   bool isExact = false;
   APSInt result(5, /*isUnsigned=*/true);

>From 41b9bef692426a9e95a31393f07cb49fb59c29f6 Mon Sep 17 00:00:00 2001
From: Ariel Burton <ariel.burton at ibm.com>
Date: Tue, 16 Jul 2024 21:17:24 +0000
Subject: [PATCH 2/2] Fix formatting

---
 llvm/include/llvm/ADT/APFloat.h    | 14 ++++----
 llvm/lib/Support/APFloat.cpp       | 52 ++++++++++++++---------------
 llvm/unittests/ADT/APFloatTest.cpp | 53 +++++++++++++++++-------------
 3 files changed, 65 insertions(+), 54 deletions(-)

diff --git a/llvm/include/llvm/ADT/APFloat.h b/llvm/include/llvm/ADT/APFloat.h
index f2ed3a5d22b82..89ea8ee7d5bda 100644
--- a/llvm/include/llvm/ADT/APFloat.h
+++ b/llvm/include/llvm/ADT/APFloat.h
@@ -15,10 +15,10 @@
 #ifndef LLVM_ADT_APFLOAT_H
 #define LLVM_ADT_APFLOAT_H
 
-#include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/APInt.h"
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/FloatingPointMode.h"
+#include "llvm/ADT/SmallString.h"
 #include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/NativeFormatting.h"
 #include "llvm/Support/float128.h"
@@ -567,6 +567,7 @@ class IEEEFloat final : public APFloatBase {
 
   /// decompose to an integer and exponent to radix 2
   bool decomposeToIntegerAndPowerOf2(APInt &, int &) const;
+
 private:
   /// \name Simple Queries
   /// @{
@@ -1398,13 +1399,14 @@ class APFloat : public APFloatBase {
   /// returns true on success, false otherwise (e.g., NaN, Infinity)
   /// similar to the standard modf, but exponent does not
   /// have to have the same sign as the value.
-  bool decomposeToIntegerAndPowerOf2 (APInt &I, int &exp) const {
-    APFLOAT_DISPATCH_ON_SEMANTICS( decomposeToIntegerAndPowerOf2(I, exp));
+  bool decomposeToIntegerAndPowerOf2(APInt &I, int &exp) const {
+    APFLOAT_DISPATCH_ON_SEMANTICS(decomposeToIntegerAndPowerOf2(I, exp));
   }
 
-  SmallVectorImpl<char> &format(SmallVectorImpl<char> &strout,
-              llvm::FloatStyle style = llvm::FloatStyle::Exponent,
-              std::optional<size_t> precision = std::nullopt);
+  SmallVectorImpl<char> &
+  format(SmallVectorImpl<char> &strout,
+         llvm::FloatStyle style = llvm::FloatStyle::Exponent,
+         std::optional<size_t> precision = std::nullopt);
 
   void print(raw_ostream &) const;
   void dump() const;
diff --git a/llvm/lib/Support/APFloat.cpp b/llvm/lib/Support/APFloat.cpp
index cf9793d6e3f76..0507d807b3a27 100644
--- a/llvm/lib/Support/APFloat.cpp
+++ b/llvm/lib/Support/APFloat.cpp
@@ -4596,12 +4596,11 @@ void IEEEFloat::makeZero(bool Negative) {
   APInt::tcSet(significandParts(), 0, partCount());
 }
 
-IEEEFloat::ExponentType IEEEFloat::getExponent() const {
-  return exponent;
-}
+IEEEFloat::ExponentType IEEEFloat::getExponent() const { return exponent; }
 
 APInt IEEEFloat::getSignificand() const {
-  APInt result(semantics->precision, ArrayRef<integerPart>(significandParts(), partCount()));
+  APInt result(semantics->precision,
+               ArrayRef<integerPart>(significandParts(), partCount()));
 
   return result;
 }
@@ -5401,8 +5400,8 @@ APFloat APFloat::getAllOnesValue(const fltSemantics &Semantics) {
 }
 
 SmallVectorImpl<char> &APFloat::format(SmallVectorImpl<char> &strout,
-                                     llvm::FloatStyle style,
-                                     std::optional<size_t> precision_in) {
+                                       llvm::FloatStyle style,
+                                       std::optional<size_t> precision_in) {
   size_t precision = precision_in.value_or(getDefaultPrecision(style));
 
   // everything that follows assumes that precision >= 0
@@ -5426,7 +5425,7 @@ SmallVectorImpl<char> &APFloat::format(SmallVectorImpl<char> &strout,
       strout.push_back('.');
       for (size_t i = 0; i < precision; ++i)
         strout.push_back('0');
-    }  
+    }
     if (style == FloatStyle::Exponent)
       detail::append(strout, "e+00");
     else if (style == FloatStyle::ExponentUpper)
@@ -5539,7 +5538,7 @@ SmallVectorImpl<char> &APFloat::format(SmallVectorImpl<char> &strout,
       // now move decimal point back
       E += (s.size() - 1);
     }
-    if(isNegative())
+    if (isNegative())
       strout.push_back('-');
     strout.push_back(s[0]);
     if (precision > 0) {
@@ -5572,7 +5571,7 @@ SmallVectorImpl<char> &APFloat::format(SmallVectorImpl<char> &strout,
       strout.push_back('0' + E);
     } else {
       s.clear();
-      while(E) {
+      while (E) {
         char c = '0' + E % 10;
         strout.push_back(c);
         E /= 10;
@@ -5585,7 +5584,7 @@ SmallVectorImpl<char> &APFloat::format(SmallVectorImpl<char> &strout,
 
   // output to be formatted along the lines of %f
   if (style == FloatStyle::Percent)
-    decimalPoint += 2;    // multiply by 100
+    decimalPoint += 2; // multiply by 100
 
   int decidingDigit = decimalPoint + precision;
 
@@ -5593,7 +5592,7 @@ SmallVectorImpl<char> &APFloat::format(SmallVectorImpl<char> &strout,
     // theh value is zero.  The deciding digit is to the left
     // of the digits in s.  This is in the area of zeros, and
     // the contents of s can't affect the value.
-  } else if (decidingDigit >= (int) s.size()) {
+  } else if (decidingDigit >= (int)s.size()) {
     // deciding is beyond the end of s
   } else if (decidingDigit == 0) {
     // this is a tricky case, because if the digit at position 0
@@ -5611,13 +5610,14 @@ SmallVectorImpl<char> &APFloat::format(SmallVectorImpl<char> &strout,
     }
   } else if (s[decidingDigit] >= '5') {
     StringRef significantDigits(s.data(), decidingDigit);
-    int distanceBetweenDecimalPointAndDecidingDigit = decidingDigit - decimalPoint;
-    APInt temp (I.getBitWidth(), significantDigits, 10);
+    int distanceBetweenDecimalPointAndDecidingDigit =
+        decidingDigit - decimalPoint;
+    APInt temp(I.getBitWidth(), significantDigits, 10);
     temp += 1;
     s.clear();
     temp.toString(s, 10, false);
     // readjust decimalPoint in case the addition had a carry out
-    decimalPoint = (int) s.size() - distanceBetweenDecimalPointAndDecidingDigit;
+    decimalPoint = (int)s.size() - distanceBetweenDecimalPointAndDecidingDigit;
   }
 
   if (isNegative())
@@ -5631,7 +5631,7 @@ SmallVectorImpl<char> &APFloat::format(SmallVectorImpl<char> &strout,
     strout.push_back('0');
   } else {
     // we need to emit decimalPoint digits
-    int fromS = std::min(decimalPoint, (int) s.size());
+    int fromS = std::min(decimalPoint, (int)s.size());
     int i;
 
     for (i = 0; i < fromS; i++)
@@ -5640,13 +5640,13 @@ SmallVectorImpl<char> &APFloat::format(SmallVectorImpl<char> &strout,
       strout.push_back('0');
   }
 
-  if (precision > 0 ) {
+  if (precision > 0) {
     // need to emit precision digits
     // We need to emit what's to the right of the decimal point.
     int i;
     strout.push_back('.');
     if (decimalPoint < 0) {
-      int numLeadingZeros = std::min((int) precision, -decimalPoint);
+      int numLeadingZeros = std::min((int)precision, -decimalPoint);
       for (i = 0; i < numLeadingZeros; i++)
         strout.push_back('0');
       // update how many digits we have left to emit
@@ -5655,17 +5655,17 @@ SmallVectorImpl<char> &APFloat::format(SmallVectorImpl<char> &strout,
       decimalPoint += numLeadingZeros;
     }
 
-    if ( precision > 0) {
+    if (precision > 0) {
       // decimalPoint must be >= 0.
-      // If it was < 0 befoew we emitted the integer to the left of the decimal ppint,
-      // then it would have been incremented by numLeadingZeros in the previous block.
-      // It would have been incremented by the smaller of |decimalPoint| and precision.
-      // if |decimalPoint| were smaller, then decimalPoint will now be 0.
-      // If precision were smaller, then precision would have been decremented to 0,
-      // so we wouldn't be in this block.
+      // If it was < 0 befoew we emitted the integer to the left of the decimal
+      // ppint, then it would have been incremented by numLeadingZeros in the
+      // previous block. It would have been incremented by the smaller of
+      // |decimalPoint| and precision. If |decimalPoint| were smaller, then
+      // decimalPoint will now be 0. If precision were smaller, then precision
+      // would have been decremented to 0, so we wouldn't be in this block.
       // Hencem if we are in this block, then decimalPoint must be >= 0.
       assert(decimalPoint >= 0);
-      if (decimalPoint < (int) s.size()) {
+      if (decimalPoint < (int)s.size()) {
         // we need to emit digits from s
         int fromS = std::min(precision, s.size() - decimalPoint);
 
@@ -5673,7 +5673,7 @@ SmallVectorImpl<char> &APFloat::format(SmallVectorImpl<char> &strout,
           strout.push_back(s[decimalPoint + i]);
         precision -= fromS;
       }
-      for ( i = 0; i < (int) precision; i++ )
+      for (i = 0; i < (int)precision; i++)
         strout.push_back('0');
     }
   }
diff --git a/llvm/unittests/ADT/APFloatTest.cpp b/llvm/unittests/ADT/APFloatTest.cpp
index a718c49dc662e..7e2f86d14ca4b 100644
--- a/llvm/unittests/ADT/APFloatTest.cpp
+++ b/llvm/unittests/ADT/APFloatTest.cpp
@@ -1379,22 +1379,22 @@ TEST(APFloatTest, toString) {
 }
 
 TEST(APFloatTest, format) {
-  auto doit_precision = [](const fltSemantics &S, const char *value, llvm::FloatStyle style, int precision, const char *expected) {
-
-    SmallString<16>  s;
+  auto doit_precision = [](const fltSemantics &S, const char *value,
+                           llvm::FloatStyle style, int precision,
+                           const char *expected) {
+    SmallString<16> s;
     APFloat apf(S, value);
     apf.format(s, style, precision);
     EXPECT_STREQ(expected, s.c_str());
   };
-  auto doit = [](const fltSemantics &S, const char *value, llvm::FloatStyle style, const char *expected) {
-
-    SmallString<16>  s;
+  auto doit = [](const fltSemantics &S, const char *value,
+                 llvm::FloatStyle style, const char *expected) {
+    SmallString<16> s;
     APFloat apf(S, value);
     apf.format(s, style);
     EXPECT_STREQ(expected, s.c_str());
   };
 
-
   // default precision for Exponent and ExponentUpper is 6
   // and 2 for Fixed and Psercent
   // All float formats should be able to handle small vlues.
@@ -1434,7 +1434,6 @@ TEST(APFloatTest, format) {
     doit(S, "-1.5", llvm::FloatStyle::Fixed, "-1.50");
     doit(S, "-1.5", llvm::FloatStyle::Percent, "-150.00%");
 
-
     // check rounding: 0
     doit_precision(S, "0.0", llvm::FloatStyle::Exponent, 0, "0e+00");
     doit_precision(S, "0.0", llvm::FloatStyle::ExponentUpper, 0, "0E+00");
@@ -1476,26 +1475,29 @@ TEST(APFloatTest, format) {
     // check appending fewer than default number of zeros
     if (Precision >= 3) {
       doit_precision(S, "1.75", llvm::FloatStyle::Exponent, 3, "1.750e+00");
-      doit_precision(S, "1.75", llvm::FloatStyle::ExponentUpper, 3, "1.750E+00");
+      doit_precision(S, "1.75", llvm::FloatStyle::ExponentUpper, 3,
+                     "1.750E+00");
       doit_precision(S, "1.75", llvm::FloatStyle::Fixed, 3, "1.750");
       doit_precision(S, "1.75", llvm::FloatStyle::Percent, 3, "175.000%");
     }
 
     // check appending more than default number of zeros
     if (Precision >= 3) {
-      doit_precision(S, "1.75", llvm::FloatStyle::Exponent, 8, "1.75000000e+00");
-      doit_precision(S, "1.75", llvm::FloatStyle::ExponentUpper, 8, "1.75000000E+00");
+      doit_precision(S, "1.75", llvm::FloatStyle::Exponent, 8,
+                     "1.75000000e+00");
+      doit_precision(S, "1.75", llvm::FloatStyle::ExponentUpper, 8,
+                     "1.75000000E+00");
       doit_precision(S, "1.75", llvm::FloatStyle::Fixed, 8, "1.75000000");
       doit_precision(S, "1.75", llvm::FloatStyle::Percent, 8, "175.00000000%");
     }
   }
 
   // test the main types with wider ranges
-  auto sems = { llvm::APFloat::S_IEEEsingle, llvm::APFloat::S_IEEEdouble,
-                llvm::APFloat::S_IEEEquad, llvm::APFloat::S_PPCDoubleDouble,
-                llvm::APFloat::S_x87DoubleExtended};
+  auto sems = {llvm::APFloat::S_IEEEsingle, llvm::APFloat::S_IEEEdouble,
+               llvm::APFloat::S_IEEEquad, llvm::APFloat::S_PPCDoubleDouble,
+               llvm::APFloat::S_x87DoubleExtended};
 
-  for ( auto sem : sems ) {
+  for (auto sem : sems) {
     const auto &S = APFloat::EnumToSemantics(sem);
 
     doit(S, "0.000001", llvm::FloatStyle::Exponent, "1.000000e-06");
@@ -1505,17 +1507,24 @@ TEST(APFloatTest, format) {
 
     // 1/1024 == 0.0009765625
     doit(S, "0.0009765625", llvm::FloatStyle::Exponent, "9.765625e-04");
-    doit_precision(S, "0.0009765625", llvm::FloatStyle::Exponent, 5, "9.76563e-04");
-    doit_precision(S, "0.0009765625", llvm::FloatStyle::Exponent, 4, "9.7656e-04");
-    doit_precision(S, "0.0009765625", llvm::FloatStyle::Exponent, 3, "9.766e-04");
-    doit_precision(S, "0.0009765625", llvm::FloatStyle::Exponent, 2, "9.77e-04");
+    doit_precision(S, "0.0009765625", llvm::FloatStyle::Exponent, 5,
+                   "9.76563e-04");
+    doit_precision(S, "0.0009765625", llvm::FloatStyle::Exponent, 4,
+                   "9.7656e-04");
+    doit_precision(S, "0.0009765625", llvm::FloatStyle::Exponent, 3,
+                   "9.766e-04");
+    doit_precision(S, "0.0009765625", llvm::FloatStyle::Exponent, 2,
+                   "9.77e-04");
     doit_precision(S, "0.0009765625", llvm::FloatStyle::Exponent, 1, "9.8e-04");
     // note change in exponent as the integer 9 goes to 10, and then to 1
     doit_precision(S, "0.0009765625", llvm::FloatStyle::Exponent, 0, "1e-03");
 
-    doit_precision(S, "0.0009765625", llvm::FloatStyle::Fixed, 11, "0.00097656250");
-    doit_precision(S, "0.0009765625", llvm::FloatStyle::Fixed, 10, "0.0009765625");
-    doit_precision(S, "0.0009765625", llvm::FloatStyle::Fixed, 9, "0.000976563");
+    doit_precision(S, "0.0009765625", llvm::FloatStyle::Fixed, 11,
+                   "0.00097656250");
+    doit_precision(S, "0.0009765625", llvm::FloatStyle::Fixed, 10,
+                   "0.0009765625");
+    doit_precision(S, "0.0009765625", llvm::FloatStyle::Fixed, 9,
+                   "0.000976563");
     doit_precision(S, "0.0009765625", llvm::FloatStyle::Fixed, 8, "0.00097656");
     doit_precision(S, "0.0009765625", llvm::FloatStyle::Fixed, 7, "0.0009766");
     doit_precision(S, "0.0009765625", llvm::FloatStyle::Fixed, 6, "0.000977");



More information about the llvm-commits mailing list