forked from OSchip/llvm-project
[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:
parent
77e0e9e17d
commit
3bc2ae951a
|
@ -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':
|
||||
|
|
|
@ -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<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);
|
||||
}
|
||||
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<InputStatementState>()) {
|
||||
io.GetIoErrorHandler().Crash(
|
||||
"InputReal64() called for a non-input I/O statement");
|
||||
"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;
|
||||
}
|
||||
return EditRealInput<53>(io, *edit, reinterpret_cast<void *>(&x));
|
||||
}
|
||||
if (!EditRealInput<PREC>(io, *edit, reinterpret_cast<void *>(&x[j]))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
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);
|
||||
bool IONAME(InputComplex32)(Cookie cookie, float x[2]) {
|
||||
return InputComplex<24, float>(cookie, x);
|
||||
}
|
||||
|
||||
bool IONAME(OutputComplex64)(Cookie cookie, double r, double z) {
|
||||
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);
|
||||
}
|
||||
return IONAME(OutputReal64)(cookie, r) && IONAME(OutputReal64)(cookie, z);
|
||||
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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue