[flang-commits] [flang] 3bc2ae9 - [flang] Add runtime I/O APIs for COMPLEX formatted input
peter klausler via flang-commits
flang-commits at lists.llvm.org
Wed Jul 22 17:52:52 PDT 2020
Author: peter klausler
Date: 2020-07-22T17:52:19-07:00
New Revision: 3bc2ae951adb6bc978c0d785cdc0bbcd923383d4
URL: https://github.com/llvm/llvm-project/commit/3bc2ae951adb6bc978c0d785cdc0bbcd923383d4
DIFF: https://github.com/llvm/llvm-project/commit/3bc2ae951adb6bc978c0d785cdc0bbcd923383d4.diff
LOG: [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
Added:
Modified:
flang/runtime/edit-input.cpp
flang/runtime/io-api.cpp
flang/runtime/io-api.h
flang/runtime/io-stmt.cpp
flang/unittests/Runtime/hello.cpp
Removed:
################################################################################
diff --git a/flang/runtime/edit-input.cpp b/flang/runtime/edit-input.cpp
index 9af2dbeb244c..ebbe41b49b2c 100644
--- a/flang/runtime/edit-input.cpp
+++ b/flang/runtime/edit-input.cpp
@@ -248,7 +248,7 @@ bool EditCommonRealInput(IoStatementState &io, const DataEdit &edit, void *n) {
int exponent{0};
int got{ScanRealInput(buffer, maxDigits + 2, io, edit, exponent)};
if (got >= maxDigits + 2) {
- io.GetIoErrorHandler().Crash("EditRealInput: buffer was too small");
+ io.GetIoErrorHandler().Crash("EditCommonRealInput: buffer was too small");
return false;
}
if (got == 0) {
@@ -277,6 +277,8 @@ template <int binaryPrecision>
bool EditRealInput(IoStatementState &io, const DataEdit &edit, void *n) {
switch (edit.descriptor) {
case DataEdit::ListDirected:
+ case DataEdit::ListDirectedRealPart:
+ case DataEdit::ListDirectedImaginaryPart:
case 'F':
case 'E': // incl. EN, ES, & EX
case 'D':
diff --git a/flang/runtime/io-api.cpp b/flang/runtime/io-api.cpp
index 5e595a93ce05..708090ac6856 100644
--- a/flang/runtime/io-api.cpp
+++ b/flang/runtime/io-api.cpp
@@ -892,86 +892,101 @@ bool IONAME(InputInteger)(Cookie cookie, std::int64_t &n, int kind) {
return false;
}
-bool IONAME(OutputReal32)(Cookie cookie, float x) {
+template <int PREC, typename REAL>
+static bool OutputReal(Cookie cookie, REAL x) {
IoStatementState &io{*cookie};
if (!io.get_if<OutputStatementState>()) {
io.GetIoErrorHandler().Crash(
- "OutputReal32() called for a non-output I/O statement");
+ "OutputReal() called for a non-output I/O statement");
return false;
}
if (auto edit{io.GetNextDataEdit()}) {
- return RealOutputEditing<24>{io, x}.Edit(*edit);
+ return RealOutputEditing<PREC>{io, x}.Edit(*edit);
}
return false;
}
-bool IONAME(InputReal32)(Cookie cookie, float &x) {
- IoStatementState &io{*cookie};
- if (!io.get_if<InputStatementState>()) {
- io.GetIoErrorHandler().Crash(
- "InputReal32() called for a non-input I/O statement");
- return false;
- }
- if (auto edit{io.GetNextDataEdit()}) {
- if (edit->descriptor == DataEdit::ListDirectedNullValue) {
- return true;
- }
- return EditRealInput<24>(io, *edit, reinterpret_cast<void *>(&x));
- }
- return false;
+bool IONAME(OutputReal32)(Cookie cookie, float x) {
+ return OutputReal<24, float>(cookie, x);
}
bool IONAME(OutputReal64)(Cookie cookie, double x) {
- IoStatementState &io{*cookie};
- if (!io.get_if<OutputStatementState>()) {
- io.GetIoErrorHandler().Crash(
- "OutputReal64() called for a non-output I/O statement");
- return false;
- }
- if (auto edit{io.GetNextDataEdit()}) {
- return RealOutputEditing<53>{io, x}.Edit(*edit);
- }
- return false;
+ return OutputReal<53, double>(cookie, x);
}
-bool IONAME(InputReal64)(Cookie cookie, double &x) {
+template <int PREC, typename REAL>
+static bool InputReal(Cookie cookie, REAL &x) {
IoStatementState &io{*cookie};
if (!io.get_if<InputStatementState>()) {
io.GetIoErrorHandler().Crash(
- "InputReal64() called for a non-input I/O statement");
+ "InputReal() called for a non-input I/O statement");
return false;
}
if (auto edit{io.GetNextDataEdit()}) {
if (edit->descriptor == DataEdit::ListDirectedNullValue) {
return true;
}
- return EditRealInput<53>(io, *edit, reinterpret_cast<void *>(&x));
+ return EditRealInput<PREC>(io, *edit, reinterpret_cast<void *>(&x));
}
return false;
}
-bool IONAME(OutputComplex32)(Cookie cookie, float r, float z) {
+bool IONAME(InputReal32)(Cookie cookie, float &x) {
+ return InputReal<24, float>(cookie, x);
+}
+
+bool IONAME(InputReal64)(Cookie cookie, double &x) {
+ return InputReal<53, double>(cookie, x);
+}
+
+template <int PREC, typename REAL>
+static bool OutputComplex(Cookie cookie, REAL r, REAL z) {
IoStatementState &io{*cookie};
if (io.get_if<ListDirectedStatementState<Direction::Output>>()) {
DataEdit real, imaginary;
real.descriptor = DataEdit::ListDirectedRealPart;
imaginary.descriptor = DataEdit::ListDirectedImaginaryPart;
- return RealOutputEditing<24>{io, r}.Edit(real) &&
- RealOutputEditing<24>{io, z}.Edit(imaginary);
+ return RealOutputEditing<PREC>{io, r}.Edit(real) &&
+ RealOutputEditing<PREC>{io, z}.Edit(imaginary);
}
- return IONAME(OutputReal32)(cookie, r) && IONAME(OutputReal32)(cookie, z);
+ return OutputReal<PREC, REAL>(cookie, r) && OutputReal<PREC, REAL>(cookie, z);
+}
+
+bool IONAME(OutputComplex32)(Cookie cookie, float r, float z) {
+ return OutputComplex<24, float>(cookie, r, z);
}
bool IONAME(OutputComplex64)(Cookie cookie, double r, double z) {
+ return OutputComplex<53, double>(cookie, r, z);
+}
+
+template <int PREC, typename REAL>
+static bool InputComplex(Cookie cookie, REAL x[2]) {
IoStatementState &io{*cookie};
- if (io.get_if<ListDirectedStatementState<Direction::Output>>()) {
- DataEdit real, imaginary;
- real.descriptor = DataEdit::ListDirectedRealPart;
- imaginary.descriptor = DataEdit::ListDirectedImaginaryPart;
- return RealOutputEditing<53>{io, r}.Edit(real) &&
- RealOutputEditing<53>{io, z}.Edit(imaginary);
+ if (!io.get_if<InputStatementState>()) {
+ io.GetIoErrorHandler().Crash(
+ "InputComplex() called for a non-input I/O statement");
+ return false;
+ }
+ for (int j{0}; j < 2; ++j) {
+ if (auto edit{io.GetNextDataEdit()}) {
+ if (edit->descriptor == DataEdit::ListDirectedNullValue) {
+ return true;
+ }
+ if (!EditRealInput<PREC>(io, *edit, reinterpret_cast<void *>(&x[j]))) {
+ return false;
+ }
+ }
}
- return IONAME(OutputReal64)(cookie, r) && IONAME(OutputReal64)(cookie, z);
+ return true;
+}
+
+bool IONAME(InputComplex32)(Cookie cookie, float x[2]) {
+ return InputComplex<24, float>(cookie, x);
+}
+
+bool IONAME(InputComplex64)(Cookie cookie, double x[2]) {
+ return InputComplex<53, double>(cookie, x);
}
bool IONAME(OutputAscii)(Cookie cookie, const char *x, std::size_t length) {
diff --git a/flang/runtime/io-api.h b/flang/runtime/io-api.h
index a540076c2d15..f6ebc63e3f3d 100644
--- a/flang/runtime/io-api.h
+++ b/flang/runtime/io-api.h
@@ -222,7 +222,9 @@ bool IONAME(InputReal32)(Cookie, float &);
bool IONAME(OutputReal64)(Cookie, double);
bool IONAME(InputReal64)(Cookie, double &);
bool IONAME(OutputComplex32)(Cookie, float, float);
+bool IONAME(InputComplex32)(Cookie, float[2]);
bool IONAME(OutputComplex64)(Cookie, double, double);
+bool IONAME(InputComplex64)(Cookie, double[2]);
bool IONAME(OutputAscii)(Cookie, const char *, std::size_t);
bool IONAME(InputAscii)(Cookie, char *, std::size_t);
bool IONAME(OutputLogical)(Cookie, bool);
diff --git a/flang/runtime/io-stmt.cpp b/flang/runtime/io-stmt.cpp
index 95c0b9b8e166..b8e7781f235b 100644
--- a/flang/runtime/io-stmt.cpp
+++ b/flang/runtime/io-stmt.cpp
@@ -509,6 +509,7 @@ ListDirectedStatementState<Direction::Input>::GetNextDataEdit(
} else if (realPart_) {
realPart_ = false;
imaginaryPart_ = true;
+ edit.descriptor = DataEdit::ListDirectedImaginaryPart;
}
if (!ch) {
return std::nullopt;
@@ -574,6 +575,7 @@ ListDirectedStatementState<Direction::Input>::GetNextDataEdit(
if (!imaginaryPart_ && ch && *ch == '(') {
realPart_ = true;
io.HandleRelativePosition(1);
+ edit.descriptor = DataEdit::ListDirectedRealPart;
}
return edit;
}
diff --git a/flang/unittests/Runtime/hello.cpp b/flang/unittests/Runtime/hello.cpp
index 0543571bbb57..f6db4a8e47dc 100644
--- a/flang/unittests/Runtime/hello.cpp
+++ b/flang/unittests/Runtime/hello.cpp
@@ -81,6 +81,43 @@ static void multiline() {
}
}
+static void listInputTest() {
+ static const char input[]{",1*,(5.,6..)"};
+ auto cookie{IONAME(BeginInternalListInput)(input, sizeof input - 1)};
+ float z[6];
+ for (int j{0}; j < 6; ++j) {
+ z[j] = -(j + 1);
+ }
+ for (int j{0}; j < 6; j += 2) {
+ if (!IONAME(InputComplex32)(cookie, &z[j])) {
+ Fail() << "InputComplex32 failed\n";
+ }
+ }
+ auto status{IONAME(EndIoStatement)(cookie)};
+ if (status) {
+ Fail() << "Failed complex list-directed input, status "
+ << static_cast<int>(status) << '\n';
+ } else {
+ char output[33];
+ output[32] = '\0';
+ cookie = IONAME(BeginInternalListOutput)(output, 32);
+ for (int j{0}; j < 6; j += 2) {
+ if (!IONAME(OutputComplex32)(cookie, z[j], z[j + 1])) {
+ Fail() << "OutputComplex32 failed\n";
+ }
+ }
+ status = IONAME(EndIoStatement)(cookie);
+ static const char expect[33]{" (-1.,-2.) (-3.,-4.) (5.,6.) "};
+ if (status) {
+ Fail() << "Failed complex list-directed output, status "
+ << static_cast<int>(status) << '\n';
+ } else if (std::strncmp(output, expect, 33) != 0) {
+ Fail() << "Failed complex list-directed output, expected '" << expect
+ << "', but got '" << output << "'\n";
+ }
+ }
+}
+
static void realTest(const char *format, double x, const char *expect) {
char buffer[800];
auto cookie{IONAME(BeginInternalFormattedOutput)(
@@ -444,5 +481,7 @@ int main() {
realInTest("(BZ,F18.0)", " 125 ", 0x4093880000000000); // 1250
realInTest("(DC,F18.0)", " 12,5", 0x4029000000000000);
+ listInputTest();
+
return EndTests();
}
More information about the flang-commits
mailing list