Skip to content
Open
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
e2922a1
[flang][flang-rt][F202X][Issue #178494] Implement F202X leading-zero …
laoshd Feb 26, 2026
0bc9c91
Merge branch 'main' into users/laoshd/I-178494
laoshd Feb 26, 2026
e148a59
Merge branch 'main' into users/laoshd/I-178494
laoshd Feb 26, 2026
4955f1d
[flang][flang-rt][F202X][Issue #178494] Re-add tests for leading-zero…
laoshd Feb 26, 2026
3895bfe
Merge branch 'main' into users/laoshd/I-178494
laoshd Feb 26, 2026
84552d4
Merge branch 'main' into users/laoshd/I-178494
laoshd Feb 26, 2026
b4a013f
[flang][flang-rt][F202X][Issue #178494] Minor updates on comments and…
laoshd Feb 27, 2026
deaaf8a
[flang][flang-rt][F202X][Issue #178494] Update code format based on P…
laoshd Feb 27, 2026
4e7bdca
[flang][flang-rt] Update code format based on PR review.
laoshd Feb 27, 2026
9d45382
Change file name io17.f90 to io18.f90 in flang/test/Semantics to reso…
laoshd Mar 5, 2026
786c706
Merge branch 'main' into users/laoshd/I-178494
laoshd Mar 5, 2026
c733fab
Fix a flang-rt failure for 'F0.d': print leading zero only when field…
laoshd Mar 6, 2026
5b68726
Remove unnecessary default parameter value.
laoshd Mar 11, 2026
29253ec
Re-implement with editingFlags replacing enum.
laoshd Mar 12, 2026
9a45c38
Merge branch 'llvm:main' into users/laoshd/I-178494
laoshd Mar 13, 2026
f357187
Implement LEADING_ZERO= specifier for OPEN, INQUIRE and WRITE stateme…
laoshd Mar 14, 2026
4ced144
Update code format to be compliant with git-clang-format
laoshd Mar 14, 2026
ee77ec7
Add SetLeadingZero function to RuntimeFunctions.inc and update tests …
laoshd Mar 20, 2026
bfe2a4e
Add F'2023 before constraint number; Remove duplicated check from Lea…
laoshd Mar 20, 2026
3947f5b
Change calling TEST() to TEST_F() which is the correct handler for Cr…
laoshd Mar 20, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 27 additions & 2 deletions flang-rt/include/flang-rt/runtime/format-implementation.h
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ static RT_API_ATTRS bool AbsoluteTabbing(CONTEXT &context, int n) {

template <typename CONTEXT>
static RT_API_ATTRS void HandleControl(
CONTEXT &context, char ch, char next, int n) {
CONTEXT &context, char ch, char next, int n, char next2 = '\0') {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are there calls to HandleControl() that need this default value for the new parameter?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch. The default value is unnecessary. Will remove it.

MutableModes &modes{context.mutableModes()};
switch (ch) {
case 'B':
Expand Down Expand Up @@ -251,6 +251,21 @@ static RT_API_ATTRS void HandleControl(
return;
}
break;
case 'L':
if (next == 'Z') {
if (next2 == 'S') {
// LZS - suppress leading zeros
modes.leadingZero = MutableModes::LeadingZeroMode::Suppress;
} else if (next2 == 'P') {
// LZP - print leading zero
modes.leadingZero = MutableModes::LeadingZeroMode::Print;
} else {
// LZ - processor-dependent (default behavior)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is there a distinct enumeration for LZ? It always maps to one of the other two settings.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LZP will always print the leading zero, LZS will never print, LZ will print or not depending on "processor-defined". This three-way distinction matches the standard's intent.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"The leading zero mode controls optional leading zero characters in numeric output fields. When the leading zero
mode is PRINT, the processor shall produce a leading zero in any position that normally contains an optional
leading zero. When the leading zero mode is SUPPRESS, the processor shall not produce a leading zero in such
positions. When the leading zero mode is PROCESSOR_DEFINED, the processor has the option of producing
a leading zero or not in such positions, subject to 13.7.2(5)."

modes.leadingZero = MutableModes::LeadingZeroMode::Processor;
}
return;
}
break;
case 'S':
if (next == 'P') {
modes.editingFlags |= signPlus;
Expand Down Expand Up @@ -455,6 +470,7 @@ RT_API_ATTRS int FormatControl<CONTEXT>::CueUpNextDataEdit(
} else if (ch >= 'A' && ch <= 'Z') {
int start{offset_ - 1};
CharType next{'\0'};
CharType next2{'\0'};
if (ch != 'P') { // 1PE5.2 - comma not required (C1302)
CharType peek{Capitalize(PeekNext())};
if (peek >= 'A' && peek <= 'Z') {
Expand All @@ -464,6 +480,15 @@ RT_API_ATTRS int FormatControl<CONTEXT>::CueUpNextDataEdit(
// Assume a two-letter edit descriptor
next = peek;
++offset_;
} else if (ch == 'L' && peek == 'Z') {
// LZ, LZS, or LZP control edit descriptor
next = peek;
++offset_;
CharType peek2{Capitalize(PeekNext())};
if (peek2 == 'S' || peek2 == 'P') {
next2 = peek2;
++offset_;
}
} else {
// extension: assume a comma between 'ch' and 'peek'
}
Expand All @@ -484,7 +509,7 @@ RT_API_ATTRS int FormatControl<CONTEXT>::CueUpNextDataEdit(
repeat = GetIntField(context);
}
HandleControl(context, static_cast<char>(ch), static_cast<char>(next),
repeat ? *repeat : 1);
repeat ? *repeat : 1, static_cast<char>(next2));
}
} else if (ch == '/') {
context.AdvanceRecord(repeat && *repeat > 0 ? *repeat : 1);
Expand Down
7 changes: 7 additions & 0 deletions flang-rt/include/flang-rt/runtime/format.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,12 @@ struct MutableModes {
return editingFlags & decimalComma ? char32_t{','} : char32_t{'.'};
}

enum class LeadingZeroMode : std::uint8_t {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could just be a new editing flag, like BN or DP.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LZ/LZP/LZS is a three-way choice. It cannot be done by a flag.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LZ means either LZP or LZS, and those two only require one bit to distinguish them.

Processor, // LZ: processor-dependent (default)
Suppress, // LZS: suppress optional leading zero
Print, // LZP: print optional leading zero
};

std::uint8_t editingFlags{0}; // BN, DP, SS
enum decimal::FortranRounding round{
executionEnvironment
Expand All @@ -53,6 +59,7 @@ struct MutableModes {
short scale{0}; // kP
bool inNamelist{false}; // skip ! comments
bool nonAdvancing{false}; // ADVANCE='NO', or $ or \ in FORMAT
LeadingZeroMode leadingZero{LeadingZeroMode::Processor}; // LZ/LZS/LZP
};

// A single edit descriptor extracted from a FORMAT
Expand Down
45 changes: 39 additions & 6 deletions flang-rt/lib/runtime/edit-output.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -419,10 +419,28 @@ RT_API_ATTRS bool RealOutputEditing<KIND>::EditEorDOutput(
if (totalLength > width || !exponent) {
return EmitRepeated(io_, '*', width);
}
if (totalLength < width && digitsBeforePoint == 0 &&
zeroesBeforePoint == 0) {
zeroesBeforePoint = 1;
++totalLength;
if (digitsBeforePoint == 0 && zeroesBeforePoint == 0 && scale <= 0) {
// Optional leading zero position (F202X leading zero control).
// When scale > 0 (kP with k > 0), digits are moved before the decimal
// point, so the leading zero position is not optional -- skip this.
// Value has no digits before the decimal point: "0.xxxE+yy" vs ".xxxE+yy"
switch (edit.modes.leadingZero) {
case MutableModes::LeadingZeroMode::Print:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't how the edit descriptors' behaviors are defined in 13.8.5. Please conform to the standard when adding new standard features. LZP should behave in the way that you defined LZ, and LZ should behave like LZS or LZP.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My understanding of the standard is that: LZP means PRINT, alway prints the leading zero; LZS means SUPPRESS, never prints the leading zero; and LZ means PROCESSOR_DEFINED, the processor has option of printing or not (behavior the same as no leading zero edit descriptor is used).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LZP prints a leading zero when there's room for it. LZS doesn't. LZ maps to one or the other of these.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok. I re-implemented it with editingFlags replacing enum, and made it match this request. Would you review it again please.

// LZP: always print the optional leading zero
zeroesBeforePoint = 1;
++totalLength;
break;
case MutableModes::LeadingZeroMode::Suppress:
// LZS: never print the optional leading zero
break;
case MutableModes::LeadingZeroMode::Processor:
// LZ: processor-defined; add leading zero only when field has room
if (totalLength < width) {
zeroesBeforePoint = 1;
++totalLength;
}
break;
}
}
if (totalLength < width && editWidth == 0) {
width = totalLength;
Expand Down Expand Up @@ -552,7 +570,21 @@ RT_API_ATTRS bool RealOutputEditing<KIND>::EditFOutput(const DataEdit &edit) {
if (digitsBeforePoint + zeroesBeforePoint + zeroesAfterPoint +
digitsAfterPoint + trailingZeroes ==
0) {
zeroesBeforePoint = 1; // "." -> "0."
zeroesBeforePoint = 1; // "."--> "0." (bare decimal point)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"." would be a bare decimal point. "0." is not one.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Improved.

} else if (digitsBeforePoint == 0 && zeroesBeforePoint == 0 && expo <= 0) {
// Optional leading zero position (F202X leading zero control).
// Value magnitude < 1: "0.xxx" vs ".xxx"
switch (edit.modes.leadingZero) {
case MutableModes::LeadingZeroMode::Print:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See above. This is not how the modes are defined in the standard.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Explained above.

// LZP: always print the optional leading zero
zeroesBeforePoint = 1;
break;
case MutableModes::LeadingZeroMode::Suppress:
// LZS: never print the optional leading zero
break;
case MutableModes::LeadingZeroMode::Processor:
break; // handled below after width computation
}
}
int totalLength{signLength + digitsBeforePoint + zeroesBeforePoint +
1 /*'.'*/ + zeroesAfterPoint + digitsAfterPoint + trailingZeroes +
Expand All @@ -561,7 +593,8 @@ RT_API_ATTRS bool RealOutputEditing<KIND>::EditFOutput(const DataEdit &edit) {
if (totalLength > width) {
return EmitRepeated(io_, '*', width);
}
if (totalLength < width && digitsBeforePoint + zeroesBeforePoint == 0) {
if (edit.modes.leadingZero == MutableModes::LeadingZeroMode::Processor &&
totalLength < width && digitsBeforePoint + zeroesBeforePoint == 0) {
zeroesBeforePoint = 1;
++totalLength;
}
Expand Down
1 change: 1 addition & 0 deletions flang-rt/unittests/Runtime/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ add_flangrt_unittest(RuntimeTests
Format.cpp
InputExtensions.cpp
Inquiry.cpp
LeadingZeroTest.cpp
ListInputTest.cpp
LogicalFormatTest.cpp
Matmul.cpp
Expand Down
Loading