[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
This commit is contained in:
peter klausler 2020-07-22 17:01:22 -07:00
parent 77e0e9e17d
commit 3bc2ae951a
5 changed files with 117 additions and 57 deletions

View File

@ -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':

View File

@ -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(OutputReal32)(Cookie cookie, float x) {
return OutputReal<24, float>(cookie, x);
}
bool IONAME(OutputReal64)(Cookie cookie, double x) {
return OutputReal<53, double>(cookie, x);
}
template <int PREC, typename REAL>
static bool InputReal(Cookie cookie, REAL &x) {
IoStatementState &io{*cookie};
if (!io.get_if<InputStatementState>()) {
io.GetIoErrorHandler().Crash(
"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<PREC>(io, *edit, reinterpret_cast<void *>(&x));
}
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(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 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<InputStatementState>()) {
io.GetIoErrorHandler().Crash(
"InputReal64() called for a non-input I/O statement");
return false;
if (io.get_if<ListDirectedStatementState<Direction::Output>>()) {
DataEdit real, imaginary;
real.descriptor = DataEdit::ListDirectedRealPart;
imaginary.descriptor = DataEdit::ListDirectedImaginaryPart;
return RealOutputEditing<PREC>{io, r}.Edit(real) &&
RealOutputEditing<PREC>{io, z}.Edit(imaginary);
}
if (auto edit{io.GetNextDataEdit()}) {
if (edit->descriptor == DataEdit::ListDirectedNullValue) {
return true;
}
return EditRealInput<53>(io, *edit, reinterpret_cast<void *>(&x));
}
return false;
return OutputReal<PREC, REAL>(cookie, r) && OutputReal<PREC, REAL>(cookie, z);
}
bool IONAME(OutputComplex32)(Cookie cookie, float r, float 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 IONAME(OutputReal32)(cookie, r) && IONAME(OutputReal32)(cookie, 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;
}
return IONAME(OutputReal64)(cookie, r) && IONAME(OutputReal64)(cookie, z);
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 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) {

View File

@ -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);

View File

@ -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;
}

View File

@ -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();
}