Skip to content

Commit add189c

Browse files
authored
[flang][runtime] Resume rounding hexadecimal floating-point input (#77006)
This reverts commit cab156c, and adds language to Extensions.md documenting the discrepancy with the letter of the language standard.
1 parent 1d18930 commit add189c

File tree

2 files changed

+39
-8
lines changed

2 files changed

+39
-8
lines changed

flang/docs/Extensions.md

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -651,11 +651,10 @@ end
651651
only in function references, but not an explicit `INTRINSIC` statement,
652652
its name is not brought into other scopes by a `USE` statement.
653653

654-
* Should hexadecimal floating-point input editing apply any rounding?
655-
F'2023 subclause 13.7.2.3.8 only discusses rounding in the context of
656-
decimal-to-binary conversion; it would seem to not apply, and so
657-
we don't round. This seems to be how the Intel Fortran compilers
658-
behave.
654+
* The subclause on rounding in formatted I/O (13.7.2.3.8 in F'2023)
655+
only discusses rounding for decimal-to/from-binary conversions,
656+
omitting any mention of rounding for hexadecimal conversions.
657+
As other compilers do apply rounding, so does this one.
659658

660659
* For real `MAXVAL`, `MINVAL`, `MAXLOC`, and `MINLOC`, NaN values are
661660
essentially ignored unless there are some unmasked array entries and

flang/runtime/edit-input.cpp

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -632,6 +632,31 @@ decimal::ConversionToBinaryResult<binaryPrecision> ConvertHexadecimal(
632632
fraction <<= 1;
633633
--expo;
634634
}
635+
// Rounding
636+
bool increase{false};
637+
switch (rounding) {
638+
case decimal::RoundNearest: // RN & RP
639+
increase = roundingBit && (guardBit | ((int)fraction & 1));
640+
break;
641+
case decimal::RoundUp: // RU
642+
increase = !isNegative && (roundingBit | guardBit);
643+
break;
644+
case decimal::RoundDown: // RD
645+
increase = isNegative && (roundingBit | guardBit);
646+
break;
647+
case decimal::RoundToZero: // RZ
648+
break;
649+
case decimal::RoundCompatible: // RC
650+
increase = roundingBit != 0;
651+
break;
652+
}
653+
if (increase) {
654+
++fraction;
655+
if (fraction >> binaryPrecision) {
656+
fraction >>= 1;
657+
++expo;
658+
}
659+
}
635660
}
636661
// Package & return result
637662
constexpr RawType significandMask{(one << RealType::significandBits) - 1};
@@ -642,9 +667,16 @@ decimal::ConversionToBinaryResult<binaryPrecision> ConvertHexadecimal(
642667
expo = 0; // subnormal
643668
flags |= decimal::Underflow;
644669
} else if (expo >= RealType::maxExponent) {
645-
expo = RealType::maxExponent; // +/-Inf
646-
fraction = 0;
647-
flags |= decimal::Overflow;
670+
if (rounding == decimal::RoundToZero ||
671+
(rounding == decimal::RoundDown && !isNegative) ||
672+
(rounding == decimal::RoundUp && isNegative)) {
673+
expo = RealType::maxExponent - 1; // +/-HUGE()
674+
fraction = significandMask;
675+
} else {
676+
expo = RealType::maxExponent; // +/-Inf
677+
fraction = 0;
678+
flags |= decimal::Overflow;
679+
}
648680
} else {
649681
fraction &= significandMask; // remove explicit normalization unless x87
650682
}

0 commit comments

Comments
 (0)