================
@@ -5865,257 +5933,2301 @@ DoubleAPFloat frexp(const DoubleAPFloat &Arg, int
&Exp,
std::move(Second));
}
-} // namespace detail
-
-APFloat::Storage::Storage(IEEEFloat F, const fltSemantics &Semantics) {
- if (usesLayout<IEEEFloat>(Semantics)) {
- new (&IEEE) IEEEFloat(std::move(F));
- return;
- }
- if (usesLayout<DoubleAPFloat>(Semantics)) {
- const fltSemantics& S = F.getSemantics();
- new (&Double) DoubleAPFloat(Semantics, APFloat(std::move(F), S),
- APFloat(APFloatBase::IEEEdouble()));
- return;
- }
- llvm_unreachable("Unexpected semantics");
-}
+// class HexFloatArith implements HFP arithmetic using the conventions
+// and approaches of the arith library used by the IBM XL compiler,
+// and matches the behaviour of the hardware.
+class HexFloatArith {
+public:
+ struct value_t {
+ int sign; // -1 for negative, +1 for positive
+ int exponent;
+ APInt fraction;
+ };
+ static void fetch(const HexFloat &in, value_t &out);
+ static void align(value_t &, value_t &, bool sticky = false);
+ static void add(value_t &, const value_t &);
+ static void sub(value_t &, const value_t &);
+ static void mult(value_t &, const value_t &);
+ static void divide(value_t &, const value_t &);
+ static void norm(value_t &);
+ static int putres(const value_t &, HexFloat &);
+};
-Expected<APFloat::opStatus> APFloat::convertFromString(StringRef Str,
- roundingMode RM) {
- APFLOAT_DISPATCH_ON_SEMANTICS(convertFromString(Str, RM));
+unsigned int HexFloat::getNumPrecisionBits(const fltSemantics *semantics) {
+ assert(APFloat::usesLayout<HexFloat>(*semantics) && "not a HexFloat");
+ return 4 * semantics->precision;
}
-hash_code hash_value(const APFloat &Arg) {
- if (APFloat::usesLayout<detail::IEEEFloat>(Arg.getSemantics()))
- return hash_value(Arg.U.IEEE);
- if (APFloat::usesLayout<detail::DoubleAPFloat>(Arg.getSemantics()))
- return hash_value(Arg.U.Double);
- llvm_unreachable("Unexpected semantics");
+void HexFloat::initialize(const fltSemantics *ourSemantics) {
+ semantics = ourSemantics;
+ significand = APInt(getNumPrecisionBits(semantics), 0);
+ makeZero(/* IsNegative */ false);
}
-APFloat::APFloat(const fltSemantics &Semantics, StringRef S)
- : APFloat(Semantics) {
- auto StatusOrErr = convertFromString(S, rmNearestTiesToEven);
- assert(StatusOrErr && "Invalid floating point representation");
- consumeError(StatusOrErr.takeError());
+void HexFloat::assign(const HexFloat &rhs) {
+ assert(semantics == rhs.semantics);
+ sign = rhs.sign;
+ exponent = rhs.exponent;
+ significand = rhs.significand;
+ low_sign = rhs.low_sign;
+ low_exponent = rhs.low_exponent;
}
-FPClassTest APFloat::classify() const {
- if (isZero())
- return isNegative() ? fcNegZero : fcPosZero;
- if (isNormal())
- return isNegative() ? fcNegNormal : fcPosNormal;
- if (isDenormal())
- return isNegative() ? fcNegSubnormal : fcPosSubnormal;
- if (isInfinity())
- return isNegative() ? fcNegInf : fcPosInf;
- assert(isNaN() && "Other class of FP constant");
- return isSignaling() ? fcSNan : fcQNan;
+HexFloat::HexFloat(const fltSemantics &ourSemantics)
+ : semantics(&ourSemantics) {
+ initialize(&ourSemantics);
}
-bool APFloat::getExactInverse(APFloat *Inv) const {
- // Only finite, non-zero numbers can have a useful, representable inverse.
- // This check filters out +/- zero, +/- infinity, and NaN.
- if (!isFiniteNonZero())
- return false;
-
- // Historically, this function rejects subnormal inputs. One reason why this
- // might be important is that subnormals may behave differently under FTZ/DAZ
- // runtime behavior.
- if (isDenormal())
- return false;
-
- // A number has an exact, representable inverse if and only if it is a power
- // of two.
- //
- // Mathematical Rationale:
- // 1. A binary floating-point number x is a dyadic rational, meaning it can
- // be written as x = M / 2^k for integers M (the significand) and k.
- // 2. The inverse is 1/x = 2^k / M.
- // 3. For 1/x to also be a dyadic rational (and thus exactly representable
- // in binary), its denominator M must also be a power of two.
- // Let's say M = 2^m.
- // 4. Substituting this back into the formula for x, we get
- // x = (2^m) / (2^k) = 2^(m-k).
- //
- // This proves that x must be a power of two.
-
- // getExactLog2Abs() returns the integer exponent if the number is a power of
- // two or INT_MIN if it is not.
- const int Exp = getExactLog2Abs();
- if (Exp == INT_MIN)
- return false;
-
- // The inverse of +/- 2^Exp is +/- 2^(-Exp). We can compute this by
- // scaling 1.0 by the negated exponent.
- APFloat Reciprocal =
- scalbn(APFloat::getOne(getSemantics(), /*Negative=*/isNegative()), -Exp,
- rmTowardZero);
+HexFloat::HexFloat(const fltSemantics &ourSemantics, integerPart intValue)
+ : semantics(&ourSemantics) {
+ initialize(&ourSemantics);
+ static_assert(sizeof(intValue) <= sizeof(uint64_t));
+ if (!intValue) {
+ // initialize will have set us to zero
+ return;
+ }
- // scalbn might round if the resulting exponent -Exp is outside the
- // representable range, causing overflow (to infinity) or underflow. We
- // must verify that the result is still the exact power of two we expect.
- if (Reciprocal.getExactLog2Abs() != -Exp)
- return false;
+ // intValue is regarded as an integer.
+ // Therefore its radix point is to the right of intValue.
+ // HexFloat has the radix point to the left of the significand,
+ // therefore we initialize the exponent to the number of hexits
+ // intValue could contain. We then normalize, decremeting exponent
+ // each time we shift.
- // Avoid multiplication with a subnormal, it is not safe on all platforms and
- // may be slower than a normal division.
- if (Reciprocal.isDenormal())
- return false;
+ APInt working_significand(sizeof(intValue) * 8, intValue);
+ APInt mask(working_significand.getBitWidth(), 0);
+ mask.setBit(mask.getBitWidth() - 4); // lowest bit of top hexit
+ // the corresponding constructor for IEEE seems to assume that the
+ // value cannot be negative.
+ sign = 0;
+ exponent = (sizeof(intValue) * 8) / 4;
+ // normalize
+ while (mask.ugt(working_significand)) {
+ working_significand <<= 4;
+ exponent--;
+ }
+ int delta_width =
+ working_significand.getBitWidth() - significand.getBitWidth();
+ if (delta_width > 0) {
+ // HexFloat always rounds towards 0, so truncate is adequate
+ // APInt:trunc truncates on left
+ working_significand = working_significand.lshr(delta_width);
+ working_significand = working_significand.trunc(significand.getBitWidth());
+ } else if (delta_width < 0) {
+ // APInt::zext extends on left
+ working_significand = working_significand.zext(significand.getBitWidth());
+ working_significand <<= -delta_width;
+ }
+ significand = working_significand;
+}
- assert(Reciprocal.isFiniteNonZero());
+HexFloat::HexFloat(const fltSemantics &ourSemantics, uninitializedTag)
+ : semantics(&ourSemantics) {
+ initialize(&ourSemantics);
+}
- if (Inv)
- *Inv = std::move(Reciprocal);
+HexFloat::HexFloat(const fltSemantics &ourSemantics,
+ const APInt &EncodedHexFloat)
+ : semantics(&ourSemantics) {
+ initialize(&ourSemantics);
+ assert(semantics == &ourSemantics && "semantics not initialized as
expected");
- return true;
-}
+ assert(EncodedHexFloat.getBitWidth() == semantics->sizeInBits &&
+ "EncodedHexFloat has unexpected size");
-APFloat::opStatus APFloat::convert(const fltSemantics &ToSemantics,
- roundingMode RM, bool *losesInfo) {
- if (&getSemantics() == &ToSemantics) {
- *losesInfo = false;
- return opOK;
- }
- if (usesLayout<IEEEFloat>(getSemantics()) &&
- usesLayout<IEEEFloat>(ToSemantics))
- return U.IEEE.convert(ToSemantics, RM, losesInfo);
- if (usesLayout<IEEEFloat>(getSemantics()) &&
- usesLayout<DoubleAPFloat>(ToSemantics)) {
- assert(&ToSemantics == &APFloatBase::semPPCDoubleDouble);
- auto Ret =
- U.IEEE.convert(APFloatBase::semPPCDoubleDoubleLegacy, RM, losesInfo);
- *this = APFloat(ToSemantics, U.IEEE.bitcastToAPInt());
- return Ret;
- }
- if (usesLayout<DoubleAPFloat>(getSemantics()) &&
- usesLayout<IEEEFloat>(ToSemantics)) {
- auto Ret = getIEEE().convert(ToSemantics, RM, losesInfo);
- *this = APFloat(std::move(getIEEE()), ToSemantics);
- return Ret;
+ auto get_sign_exponent = [](const APInt &i, int &s, int &e) {
+ auto left_byte = i.getHiBits(8).trunc(8).getLimitedValue();
+ s = (left_byte & 0x80) ? 1 : 0;
+ e = (left_byte & 0x7f) - 64;
+ };
+ int s, e;
+ get_sign_exponent(EncodedHexFloat, s, e);
+ sign = s;
+ exponent = e;
+ if (semantics == &APFloatBase::HexFP128()) {
+ // we need to remove the sign/exponent byte from the lower order 64 bit
+ // value, and save them.
+ // We then need to form the significand from the low 56 bits of each part.
+ APInt low(EncodedHexFloat.trunc(64));
+ APInt high(EncodedHexFloat.lshr(64).trunc(64));
+ APInt low_significand(low.trunc(56).zext(112));
+ APInt high_significand(high.trunc(56).zext(112));
+ high_significand <<= 56;
+ significand = high_significand | low_significand;
+ get_sign_exponent(low, s, e);
+ low_sign = s;
+ low_exponent = e;
+ } else {
+ auto NumPrecisionBits = getNumPrecisionBits(semantics);
+ significand =
+ EncodedHexFloat.getLoBits(NumPrecisionBits).trunc(NumPrecisionBits);
}
- llvm_unreachable("Unexpected semantics");
+ assert(significand.getBitWidth() == getNumPrecisionBits(semantics));
}
-APFloat APFloat::getAllOnesValue(const fltSemantics &Semantics) {
- return APFloat(Semantics, APInt::getAllOnes(Semantics.sizeInBits));
+HexFloat::HexFloat(double d) {
+ semantics = &APFloatBase::HexFP64();
+ initialize(semantics);
+ llvm_unreachable("HexFloat constructor double: cannot create from double\n");
}
-void APFloat::print(raw_ostream &OS) const {
- SmallVector<char, 16> Buffer;
- toString(Buffer);
- OS << Buffer;
+HexFloat::HexFloat(float f) {
+ semantics = &APFloatBase::HexFP32();
+ initialize(semantics);
+ llvm_unreachable("HexFloat constructor float: cannot create from float\n");
----------------
shafik wrote:
Is this unconditional unreachable intended?
https://github.com/llvm/llvm-project/pull/179771
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits