[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