Skip to content

Commit d723d14

Browse files
authored
[flang][runtime] Emit "Infinity" rather than "Inf" when required (llvm#183359)
The ISO Fortran standard requires that numeric output editing produce the full word "Infinity", rather than my current "Inf", when the output field is wide enough to hold it. Comply.
1 parent dd3d727 commit d723d14

3 files changed

Lines changed: 56 additions & 44 deletions

File tree

flang-rt/lib/runtime/edit-output.cpp

Lines changed: 40 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -266,34 +266,42 @@ RT_API_ATTRS bool RealOutputEditingBase::EmitSuffix(const DataEdit &edit) {
266266
}
267267
}
268268

269+
static RT_API_ATTRS char IsInfOrNaN(const char *p, std::size_t length) {
270+
if (!p || length < 1) {
271+
return '\0';
272+
}
273+
if (*p == '-' || *p == '+') {
274+
if (length == 1) {
275+
return '\0';
276+
}
277+
++p;
278+
}
279+
return *p == 'I' || *p == 'N' ? *p : '\0';
280+
}
281+
269282
template <int KIND>
270283
RT_API_ATTRS decimal::ConversionToDecimalResult
271-
RealOutputEditing<KIND>::ConvertToDecimal(
272-
int significantDigits, enum decimal::FortranRounding rounding, int flags) {
284+
RealOutputEditing<KIND>::ConvertToDecimal(int significantDigits,
285+
enum decimal::FortranRounding rounding, int width, int flags) {
273286
auto converted{decimal::ConvertToDecimal<binaryPrecision>(buffer_,
274287
sizeof buffer_, static_cast<enum decimal::DecimalConversionFlags>(flags),
275288
significantDigits, rounding, x_)};
276289
if (!converted.str) { // overflow
277290
io_.GetIoErrorHandler().Crash(
278291
"RealOutputEditing::ConvertToDecimal: buffer size %zd was insufficient",
279292
sizeof buffer_);
293+
} else if (IsInfOrNaN(converted.str, converted.length) == 'I' &&
294+
converted.length <= 4 &&
295+
static_cast<int>(converted.length + 5) <= width) {
296+
// Emit "Infinity" rather than "Inf" (F'2023 13.7.2.3.2 p9), possibly signed
297+
std::memcpy(buffer_, converted.str, converted.length);
298+
std::memcpy(buffer_ + converted.length, "inity", 5);
299+
converted.str = buffer_;
300+
converted.length += 5;
280301
}
281302
return converted;
282303
}
283304

284-
static RT_API_ATTRS bool IsInfOrNaN(const char *p, int length) {
285-
if (!p || length < 1) {
286-
return false;
287-
}
288-
if (*p == '-' || *p == '+') {
289-
if (length == 1) {
290-
return false;
291-
}
292-
++p;
293-
}
294-
return *p == 'I' || *p == 'N';
295-
}
296-
297305
// 13.7.2.3.3 in F'2018
298306
template <int KIND>
299307
RT_API_ATTRS bool RealOutputEditing<KIND>::EditEorDOutput(
@@ -353,9 +361,9 @@ RT_API_ATTRS bool RealOutputEditing<KIND>::EditEorDOutput(
353361
}
354362
// In EN editing, multiple attempts may be necessary, so this is a loop.
355363
while (true) {
356-
decimal::ConversionToDecimalResult converted{
357-
ConvertToDecimal(significantDigits, edit.modes.round, flags)};
358-
if (IsInfOrNaN(converted.str, static_cast<int>(converted.length))) {
364+
decimal::ConversionToDecimalResult converted{ConvertToDecimal(
365+
significantDigits, edit.modes.round, editWidth, flags)};
366+
if (IsInfOrNaN(converted.str, converted.length)) {
359367
return editWidth > 0 &&
360368
converted.length + trailingBlanks_ >
361369
static_cast<std::size_t>(editWidth)
@@ -454,9 +462,9 @@ RT_API_ATTRS bool RealOutputEditing<KIND>::EditFOutput(const DataEdit &edit) {
454462
bool canIncrease{true};
455463
for (int extraDigits{fracDigits == 0 ? 1 : 0};;) {
456464
decimal::ConversionToDecimalResult converted{
457-
ConvertToDecimal(extraDigits + fracDigits, rounding, flags)};
465+
ConvertToDecimal(extraDigits + fracDigits, rounding, editWidth, flags)};
458466
const char *convertedStr{converted.str};
459-
if (IsInfOrNaN(convertedStr, static_cast<int>(converted.length))) {
467+
if (IsInfOrNaN(converted.str, converted.length)) {
460468
return editWidth > 0 &&
461469
converted.length > static_cast<std::size_t>(editWidth)
462470
? EmitRepeated(io_, '*', editWidth)
@@ -585,8 +593,8 @@ RT_API_ATTRS DataEdit RealOutputEditing<KIND>::EditForGOutput(DataEdit edit) {
585593
flags |= decimal::AlwaysSign;
586594
}
587595
decimal::ConversionToDecimalResult converted{
588-
ConvertToDecimal(significantDigits, edit.modes.round, flags)};
589-
if (IsInfOrNaN(converted.str, static_cast<int>(converted.length))) {
596+
ConvertToDecimal(significantDigits, edit.modes.round, editWidth, flags)};
597+
if (IsInfOrNaN(converted.str, converted.length)) {
590598
return edit; // Inf/Nan -> Ew.d (same as Fw.d)
591599
}
592600
int expo{IsZero() ? 1 : converted.decimalExponent}; // 's'
@@ -619,7 +627,7 @@ RT_API_ATTRS bool RealOutputEditing<KIND>::EditListDirectedOutput(
619627
const DataEdit &edit) {
620628
decimal::ConversionToDecimalResult converted{
621629
ConvertToDecimal(1, edit.modes.round)};
622-
if (IsInfOrNaN(converted.str, static_cast<int>(converted.length))) {
630+
if (IsInfOrNaN(converted.str, converted.length)) {
623631
DataEdit copy{edit};
624632
copy.variation = DataEdit::ListDirected;
625633
return EditEorDOutput(copy);
@@ -652,15 +660,17 @@ RT_API_ATTRS bool RealOutputEditing<KIND>::EditListDirectedOutput(
652660
template <int KIND>
653661
RT_API_ATTRS auto RealOutputEditing<KIND>::ConvertToHexadecimal(
654662
int significantDigits, enum decimal::FortranRounding rounding,
655-
int flags) -> ConvertToHexadecimalResult {
663+
int editWidth, int flags) -> ConvertToHexadecimalResult {
656664
if (x_.IsNaN() || x_.IsInfinite()) {
657-
auto converted{ConvertToDecimal(significantDigits, rounding, flags)};
658-
return {converted.str, static_cast<int>(converted.length), 0};
665+
auto converted{
666+
ConvertToDecimal(significantDigits, rounding, editWidth, flags)};
667+
return {converted.str, static_cast<int>(converted.length), /*exponent=*/0};
659668
}
660669
x_.RoundToBits(4 * significantDigits, rounding);
661670
if (x_.IsInfinite()) { // rounded away to +/-Inf
662-
auto converted{ConvertToDecimal(significantDigits, rounding, flags)};
663-
return {converted.str, static_cast<int>(converted.length), 0};
671+
auto converted{
672+
ConvertToDecimal(significantDigits, rounding, editWidth, flags)};
673+
return {converted.str, static_cast<int>(converted.length), /*exponent=*/0};
664674
}
665675
int len{0};
666676
if (x_.IsNegative()) {
@@ -724,8 +734,8 @@ RT_API_ATTRS bool RealOutputEditing<KIND>::EditEXOutput(const DataEdit &edit) {
724734
(common::PrecisionOfRealKind(16) + 3) / 4};
725735
significantDigits = maxSigHexDigits;
726736
}
727-
auto converted{
728-
ConvertToHexadecimal(significantDigits, edit.modes.round, flags)};
737+
auto converted{ConvertToHexadecimal(
738+
significantDigits, edit.modes.round, editWidth, flags)};
729739
if (IsInfOrNaN(converted.str, converted.length)) {
730740
return editWidth > 0 && converted.length > editWidth
731741
? EmitRepeated(io_, '*', editWidth)

flang-rt/lib/runtime/edit-output.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,15 +77,17 @@ template <int KIND> class RealOutputEditing : public RealOutputEditingBase {
7777
RT_API_ATTRS bool IsZero() const { return x_.IsZero(); }
7878

7979
RT_API_ATTRS decimal::ConversionToDecimalResult ConvertToDecimal(
80-
int significantDigits, enum decimal::FortranRounding, int flags = 0);
80+
int significantDigits, enum decimal::FortranRounding,
81+
int width = 3 /*len("Inf")*/, int flags = 0);
8182

8283
struct ConvertToHexadecimalResult {
8384
const char *str;
8485
int length;
8586
int exponent;
8687
};
8788
RT_API_ATTRS ConvertToHexadecimalResult ConvertToHexadecimal(
88-
int significantDigits, enum decimal::FortranRounding, int flags = 0);
89+
int significantDigits, enum decimal::FortranRounding, int width,
90+
int flags);
8991

9092
BinaryFloatingPoint x_;
9193
char buffer_[BinaryFloatingPoint::maxDecimalConversionDigits +

flang-rt/unittests/Runtime/NumericalFormatTest.cpp

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -406,23 +406,23 @@ TEST(IOApiTests, FormatDoubleValues) {
406406
{// +Inf
407407
0x7ff0000000000000,
408408
{
409-
{"(E9.1,';')", " Inf;"},
410-
{"(F9.1,';')", " Inf;"},
411-
{"(G9.1,';')", " Inf;"},
412-
{"(EX9.1,';')", " Inf;"},
413-
{"(SP,E9.1,';')", " +Inf;"},
414-
{"(SP,F9.1,';')", " +Inf;"},
415-
{"(SP,G9.1,';')", " +Inf;"},
416-
{"(SP,EX9.1,';')", " +Inf;"},
409+
{"(E9.1,';')", " Infinity;"},
410+
{"(F9.1,';')", " Infinity;"},
411+
{"(G9.1,';')", " Infinity;"},
412+
{"(EX9.1,';')", " Infinity;"},
413+
{"(SP,E9.1,';')", "+Infinity;"},
414+
{"(SP,F9.1,';')", "+Infinity;"},
415+
{"(SP,G9.1,';')", "+Infinity;"},
416+
{"(SP,EX9.1,';')", "+Infinity;"},
417417
{"(G0,';')", "Inf;"},
418418
}},
419419
{// -Inf
420420
0xfff0000000000000,
421421
{
422-
{"(E9.1,';')", " -Inf;"},
423-
{"(F9.1,';')", " -Inf;"},
424-
{"(G9.1,';')", " -Inf;"},
425-
{"(EX9.1,';')", " -Inf;"},
422+
{"(E9.1,';')", "-Infinity;"},
423+
{"(F9.1,';')", "-Infinity;"},
424+
{"(G9.1,';')", "-Infinity;"},
425+
{"(EX9.1,';')", "-Infinity;"},
426426
{"(G0,';')", "-Inf;"},
427427
}},
428428
{// NaN

0 commit comments

Comments
 (0)