[flang-commits] [flang] befdfae - [flang][runtime] Detect & signal underflow when reading reals (#75232)
via flang-commits
flang-commits at lists.llvm.org
Tue Dec 26 15:00:47 PST 2023
Author: Peter Klausler
Date: 2023-12-26T15:00:43-08:00
New Revision: befdfae198a12b88bce6d26f840e6f71ce4a8b0c
URL: https://github.com/llvm/llvm-project/commit/befdfae198a12b88bce6d26f840e6f71ce4a8b0c
DIFF: https://github.com/llvm/llvm-project/commit/befdfae198a12b88bce6d26f840e6f71ce4a8b0c.diff
LOG: [flang][runtime] Detect & signal underflow when reading reals (#75232)
Extend decimal->binary conversion to detect underflow cases and raise
the corresponding floating-point exception.
Added:
Modified:
flang/include/flang/Decimal/decimal.h
flang/lib/Decimal/decimal-to-binary.cpp
flang/runtime/edit-input.cpp
Removed:
################################################################################
diff --git a/flang/include/flang/Decimal/decimal.h b/flang/include/flang/Decimal/decimal.h
index a4e0ee7c847460..f0997fb63df018 100644
--- a/flang/include/flang/Decimal/decimal.h
+++ b/flang/include/flang/Decimal/decimal.h
@@ -34,6 +34,7 @@ enum ConversionResultFlags {
Overflow = 1,
Inexact = 2,
Invalid = 4,
+ Underflow = 8,
};
struct ConversionToDecimalResult {
diff --git a/flang/lib/Decimal/decimal-to-binary.cpp b/flang/lib/Decimal/decimal-to-binary.cpp
index d5b66b9fb93388..780979f747f5ba 100644
--- a/flang/lib/Decimal/decimal-to-binary.cpp
+++ b/flang/lib/Decimal/decimal-to-binary.cpp
@@ -256,12 +256,17 @@ ConversionToBinaryResult<PREC> IntermediateFloat<PREC>::ToBinary(
if (guard != 0) {
flags |= Inexact;
}
- if (fraction == 0 && guard <= oneHalf) {
- if ((!isNegative && rounding == RoundUp) ||
- (isNegative && rounding == RoundDown)) {
- // round to minimum nonzero value
- } else {
- return {Binary{}, static_cast<enum ConversionResultFlags>(flags)};
+ if (fraction == 0) {
+ if (guard <= oneHalf) {
+ if ((!isNegative && rounding == RoundUp) ||
+ (isNegative && rounding == RoundDown)) {
+ // round to minimum nonzero value
+ } else { // round to zero
+ if (guard != 0) {
+ flags |= Underflow;
+ }
+ return {Binary{}, static_cast<enum ConversionResultFlags>(flags)};
+ }
}
} else {
// The value is nonzero; normalize it.
@@ -301,8 +306,10 @@ ConversionToBinaryResult<PREC> IntermediateFloat<PREC>::ToBinary(
}
if (expo == 1 && fraction < topBit) {
expo = 0; // subnormal
- }
- if (expo >= Binary::maxExponent) {
+ flags |= Underflow;
+ } else if (expo == 0) {
+ flags |= Underflow;
+ } else if (expo >= Binary::maxExponent) {
expo = Binary::maxExponent; // Inf
flags |= Overflow;
if constexpr (Binary::bits == 80) { // x87
@@ -338,11 +345,15 @@ BigRadixFloatingPointNumber<PREC, LOG10RADIX>::ConvertToBinary() {
// Sanity checks for ridiculous exponents
static constexpr int crazy{2 * Real::decimalRange + log10Radix};
if (exponent_ < -crazy) {
+ enum ConversionResultFlags flags {
+ static_cast<enum ConversionResultFlags>(Inexact | Underflow)
+ };
if ((!isNegative_ && rounding_ == RoundUp) ||
(isNegative_ && rounding_ == RoundDown)) {
- return {Real{Raw{1} | SignBit()}}; // return least nonzero value
+ // return least nonzero value
+ return {Real{Raw{1} | SignBit()}, flags};
} else { // underflow to +/-0.
- return {Real{SignBit()}, Inexact};
+ return {Real{SignBit()}, flags};
}
} else if (exponent_ > crazy) { // overflow to +/-Inf.
return {Real{Infinity()}, Overflow};
diff --git a/flang/runtime/edit-input.cpp b/flang/runtime/edit-input.cpp
index 822099b5141b1b..6e26e523c5ca72 100644
--- a/flang/runtime/edit-input.cpp
+++ b/flang/runtime/edit-input.cpp
@@ -478,6 +478,9 @@ static void RaiseFPExceptions(decimal::ConversionResultFlags flags) {
if (flags & decimal::ConversionResultFlags::Overflow) {
RAISE(FE_OVERFLOW);
}
+ if (flags & decimal::ConversionResultFlags::Underflow) {
+ RAISE(FE_UNDERFLOW);
+ }
if (flags & decimal::ConversionResultFlags::Inexact) {
RAISE(FE_INEXACT);
}
@@ -640,10 +643,12 @@ decimal::ConversionToBinaryResult<binaryPrecision> ConvertHexadecimal(
}
// Package & return result
constexpr RawType significandMask{(one << RealType::significandBits) - 1};
+ int flags{(roundingBit | guardBit) ? decimal::Inexact : decimal::Exact};
if (!fraction) {
expo = 0;
} else if (expo == 1 && !(fraction >> (binaryPrecision - 1))) {
expo = 0; // subnormal
+ flags |= decimal::Underflow;
} else if (expo >= RealType::maxExponent) {
expo = RealType::maxExponent; // +/-Inf
fraction = 0;
@@ -653,7 +658,7 @@ decimal::ConversionToBinaryResult<binaryPrecision> ConvertHexadecimal(
return decimal::ConversionToBinaryResult<binaryPrecision>{
RealType{static_cast<RawType>(signBit |
static_cast<RawType>(expo) << RealType::significandBits | fraction)},
- (roundingBit | guardBit) ? decimal::Inexact : decimal::Exact};
+ static_cast<enum decimal::ConversionResultFlags>(flags)};
}
template <int KIND>
More information about the flang-commits
mailing list