Skip to content

Commit 3bc2ae9

Browse files
committed
[flang] Add runtime I/O APIs for COMPLEX formatted input
It turns out that COMPLEX formatted input needs its own runtime APIs so that null values in list-directed input skip the entire COMPLEX datum rather than just a real or imaginary part thereof. Reviewed By: sscalpone Differential Revision: https://reviews.llvm.org/D84370
1 parent 77e0e9e commit 3bc2ae9

File tree

5 files changed

+102
-42
lines changed

5 files changed

+102
-42
lines changed

flang/runtime/edit-input.cpp

+3-1
Original file line numberDiff line numberDiff line change
@@ -248,7 +248,7 @@ bool EditCommonRealInput(IoStatementState &io, const DataEdit &edit, void *n) {
248248
int exponent{0};
249249
int got{ScanRealInput(buffer, maxDigits + 2, io, edit, exponent)};
250250
if (got >= maxDigits + 2) {
251-
io.GetIoErrorHandler().Crash("EditRealInput: buffer was too small");
251+
io.GetIoErrorHandler().Crash("EditCommonRealInput: buffer was too small");
252252
return false;
253253
}
254254
if (got == 0) {
@@ -277,6 +277,8 @@ template <int binaryPrecision>
277277
bool EditRealInput(IoStatementState &io, const DataEdit &edit, void *n) {
278278
switch (edit.descriptor) {
279279
case DataEdit::ListDirected:
280+
case DataEdit::ListDirectedRealPart:
281+
case DataEdit::ListDirectedImaginaryPart:
280282
case 'F':
281283
case 'E': // incl. EN, ES, & EX
282284
case 'D':

flang/runtime/io-api.cpp

+56-41
Original file line numberDiff line numberDiff line change
@@ -892,86 +892,101 @@ bool IONAME(InputInteger)(Cookie cookie, std::int64_t &n, int kind) {
892892
return false;
893893
}
894894

895-
bool IONAME(OutputReal32)(Cookie cookie, float x) {
895+
template <int PREC, typename REAL>
896+
static bool OutputReal(Cookie cookie, REAL x) {
896897
IoStatementState &io{*cookie};
897898
if (!io.get_if<OutputStatementState>()) {
898899
io.GetIoErrorHandler().Crash(
899-
"OutputReal32() called for a non-output I/O statement");
900+
"OutputReal() called for a non-output I/O statement");
900901
return false;
901902
}
902903
if (auto edit{io.GetNextDataEdit()}) {
903-
return RealOutputEditing<24>{io, x}.Edit(*edit);
904+
return RealOutputEditing<PREC>{io, x}.Edit(*edit);
904905
}
905906
return false;
906907
}
907908

908-
bool IONAME(InputReal32)(Cookie cookie, float &x) {
909-
IoStatementState &io{*cookie};
910-
if (!io.get_if<InputStatementState>()) {
911-
io.GetIoErrorHandler().Crash(
912-
"InputReal32() called for a non-input I/O statement");
913-
return false;
914-
}
915-
if (auto edit{io.GetNextDataEdit()}) {
916-
if (edit->descriptor == DataEdit::ListDirectedNullValue) {
917-
return true;
918-
}
919-
return EditRealInput<24>(io, *edit, reinterpret_cast<void *>(&x));
920-
}
921-
return false;
909+
bool IONAME(OutputReal32)(Cookie cookie, float x) {
910+
return OutputReal<24, float>(cookie, x);
922911
}
923912

924913
bool IONAME(OutputReal64)(Cookie cookie, double x) {
925-
IoStatementState &io{*cookie};
926-
if (!io.get_if<OutputStatementState>()) {
927-
io.GetIoErrorHandler().Crash(
928-
"OutputReal64() called for a non-output I/O statement");
929-
return false;
930-
}
931-
if (auto edit{io.GetNextDataEdit()}) {
932-
return RealOutputEditing<53>{io, x}.Edit(*edit);
933-
}
934-
return false;
914+
return OutputReal<53, double>(cookie, x);
935915
}
936916

937-
bool IONAME(InputReal64)(Cookie cookie, double &x) {
917+
template <int PREC, typename REAL>
918+
static bool InputReal(Cookie cookie, REAL &x) {
938919
IoStatementState &io{*cookie};
939920
if (!io.get_if<InputStatementState>()) {
940921
io.GetIoErrorHandler().Crash(
941-
"InputReal64() called for a non-input I/O statement");
922+
"InputReal() called for a non-input I/O statement");
942923
return false;
943924
}
944925
if (auto edit{io.GetNextDataEdit()}) {
945926
if (edit->descriptor == DataEdit::ListDirectedNullValue) {
946927
return true;
947928
}
948-
return EditRealInput<53>(io, *edit, reinterpret_cast<void *>(&x));
929+
return EditRealInput<PREC>(io, *edit, reinterpret_cast<void *>(&x));
949930
}
950931
return false;
951932
}
952933

953-
bool IONAME(OutputComplex32)(Cookie cookie, float r, float z) {
934+
bool IONAME(InputReal32)(Cookie cookie, float &x) {
935+
return InputReal<24, float>(cookie, x);
936+
}
937+
938+
bool IONAME(InputReal64)(Cookie cookie, double &x) {
939+
return InputReal<53, double>(cookie, x);
940+
}
941+
942+
template <int PREC, typename REAL>
943+
static bool OutputComplex(Cookie cookie, REAL r, REAL z) {
954944
IoStatementState &io{*cookie};
955945
if (io.get_if<ListDirectedStatementState<Direction::Output>>()) {
956946
DataEdit real, imaginary;
957947
real.descriptor = DataEdit::ListDirectedRealPart;
958948
imaginary.descriptor = DataEdit::ListDirectedImaginaryPart;
959-
return RealOutputEditing<24>{io, r}.Edit(real) &&
960-
RealOutputEditing<24>{io, z}.Edit(imaginary);
949+
return RealOutputEditing<PREC>{io, r}.Edit(real) &&
950+
RealOutputEditing<PREC>{io, z}.Edit(imaginary);
961951
}
962-
return IONAME(OutputReal32)(cookie, r) && IONAME(OutputReal32)(cookie, z);
952+
return OutputReal<PREC, REAL>(cookie, r) && OutputReal<PREC, REAL>(cookie, z);
953+
}
954+
955+
bool IONAME(OutputComplex32)(Cookie cookie, float r, float z) {
956+
return OutputComplex<24, float>(cookie, r, z);
963957
}
964958

965959
bool IONAME(OutputComplex64)(Cookie cookie, double r, double z) {
960+
return OutputComplex<53, double>(cookie, r, z);
961+
}
962+
963+
template <int PREC, typename REAL>
964+
static bool InputComplex(Cookie cookie, REAL x[2]) {
966965
IoStatementState &io{*cookie};
967-
if (io.get_if<ListDirectedStatementState<Direction::Output>>()) {
968-
DataEdit real, imaginary;
969-
real.descriptor = DataEdit::ListDirectedRealPart;
970-
imaginary.descriptor = DataEdit::ListDirectedImaginaryPart;
971-
return RealOutputEditing<53>{io, r}.Edit(real) &&
972-
RealOutputEditing<53>{io, z}.Edit(imaginary);
966+
if (!io.get_if<InputStatementState>()) {
967+
io.GetIoErrorHandler().Crash(
968+
"InputComplex() called for a non-input I/O statement");
969+
return false;
970+
}
971+
for (int j{0}; j < 2; ++j) {
972+
if (auto edit{io.GetNextDataEdit()}) {
973+
if (edit->descriptor == DataEdit::ListDirectedNullValue) {
974+
return true;
975+
}
976+
if (!EditRealInput<PREC>(io, *edit, reinterpret_cast<void *>(&x[j]))) {
977+
return false;
978+
}
979+
}
973980
}
974-
return IONAME(OutputReal64)(cookie, r) && IONAME(OutputReal64)(cookie, z);
981+
return true;
982+
}
983+
984+
bool IONAME(InputComplex32)(Cookie cookie, float x[2]) {
985+
return InputComplex<24, float>(cookie, x);
986+
}
987+
988+
bool IONAME(InputComplex64)(Cookie cookie, double x[2]) {
989+
return InputComplex<53, double>(cookie, x);
975990
}
976991

977992
bool IONAME(OutputAscii)(Cookie cookie, const char *x, std::size_t length) {

flang/runtime/io-api.h

+2
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,9 @@ bool IONAME(InputReal32)(Cookie, float &);
222222
bool IONAME(OutputReal64)(Cookie, double);
223223
bool IONAME(InputReal64)(Cookie, double &);
224224
bool IONAME(OutputComplex32)(Cookie, float, float);
225+
bool IONAME(InputComplex32)(Cookie, float[2]);
225226
bool IONAME(OutputComplex64)(Cookie, double, double);
227+
bool IONAME(InputComplex64)(Cookie, double[2]);
226228
bool IONAME(OutputAscii)(Cookie, const char *, std::size_t);
227229
bool IONAME(InputAscii)(Cookie, char *, std::size_t);
228230
bool IONAME(OutputLogical)(Cookie, bool);

flang/runtime/io-stmt.cpp

+2
Original file line numberDiff line numberDiff line change
@@ -509,6 +509,7 @@ ListDirectedStatementState<Direction::Input>::GetNextDataEdit(
509509
} else if (realPart_) {
510510
realPart_ = false;
511511
imaginaryPart_ = true;
512+
edit.descriptor = DataEdit::ListDirectedImaginaryPart;
512513
}
513514
if (!ch) {
514515
return std::nullopt;
@@ -574,6 +575,7 @@ ListDirectedStatementState<Direction::Input>::GetNextDataEdit(
574575
if (!imaginaryPart_ && ch && *ch == '(') {
575576
realPart_ = true;
576577
io.HandleRelativePosition(1);
578+
edit.descriptor = DataEdit::ListDirectedRealPart;
577579
}
578580
return edit;
579581
}

flang/unittests/Runtime/hello.cpp

+39
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,43 @@ static void multiline() {
8181
}
8282
}
8383

84+
static void listInputTest() {
85+
static const char input[]{",1*,(5.,6..)"};
86+
auto cookie{IONAME(BeginInternalListInput)(input, sizeof input - 1)};
87+
float z[6];
88+
for (int j{0}; j < 6; ++j) {
89+
z[j] = -(j + 1);
90+
}
91+
for (int j{0}; j < 6; j += 2) {
92+
if (!IONAME(InputComplex32)(cookie, &z[j])) {
93+
Fail() << "InputComplex32 failed\n";
94+
}
95+
}
96+
auto status{IONAME(EndIoStatement)(cookie)};
97+
if (status) {
98+
Fail() << "Failed complex list-directed input, status "
99+
<< static_cast<int>(status) << '\n';
100+
} else {
101+
char output[33];
102+
output[32] = '\0';
103+
cookie = IONAME(BeginInternalListOutput)(output, 32);
104+
for (int j{0}; j < 6; j += 2) {
105+
if (!IONAME(OutputComplex32)(cookie, z[j], z[j + 1])) {
106+
Fail() << "OutputComplex32 failed\n";
107+
}
108+
}
109+
status = IONAME(EndIoStatement)(cookie);
110+
static const char expect[33]{" (-1.,-2.) (-3.,-4.) (5.,6.) "};
111+
if (status) {
112+
Fail() << "Failed complex list-directed output, status "
113+
<< static_cast<int>(status) << '\n';
114+
} else if (std::strncmp(output, expect, 33) != 0) {
115+
Fail() << "Failed complex list-directed output, expected '" << expect
116+
<< "', but got '" << output << "'\n";
117+
}
118+
}
119+
}
120+
84121
static void realTest(const char *format, double x, const char *expect) {
85122
char buffer[800];
86123
auto cookie{IONAME(BeginInternalFormattedOutput)(
@@ -444,5 +481,7 @@ int main() {
444481
realInTest("(BZ,F18.0)", " 125 ", 0x4093880000000000); // 1250
445482
realInTest("(DC,F18.0)", " 12,5", 0x4029000000000000);
446483

484+
listInputTest();
485+
447486
return EndTests();
448487
}

0 commit comments

Comments
 (0)