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 exponent{0};
|
||||||
int got{ScanRealInput(buffer, maxDigits + 2, io, edit, exponent)};
|
int got{ScanRealInput(buffer, maxDigits + 2, io, edit, exponent)};
|
||||||
if (got >= maxDigits + 2) {
|
if (got >= maxDigits + 2) {
|
||||||
io.GetIoErrorHandler().Crash("EditRealInput: buffer was too small");
|
io.GetIoErrorHandler().Crash("EditCommonRealInput: buffer was too small");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (got == 0) {
|
if (got == 0) {
|
||||||
|
@ -277,6 +277,8 @@ template <int binaryPrecision>
|
||||||
bool EditRealInput(IoStatementState &io, const DataEdit &edit, void *n) {
|
bool EditRealInput(IoStatementState &io, const DataEdit &edit, void *n) {
|
||||||
switch (edit.descriptor) {
|
switch (edit.descriptor) {
|
||||||
case DataEdit::ListDirected:
|
case DataEdit::ListDirected:
|
||||||
|
case DataEdit::ListDirectedRealPart:
|
||||||
|
case DataEdit::ListDirectedImaginaryPart:
|
||||||
case 'F':
|
case 'F':
|
||||||
case 'E': // incl. EN, ES, & EX
|
case 'E': // incl. EN, ES, & EX
|
||||||
case 'D':
|
case 'D':
|
||||||
|
|
|
@ -892,86 +892,101 @@ bool IONAME(InputInteger)(Cookie cookie, std::int64_t &n, int kind) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IONAME(OutputReal32)(Cookie cookie, float x) {
|
template <int PREC, typename REAL>
|
||||||
|
static bool OutputReal(Cookie cookie, REAL x) {
|
||||||
IoStatementState &io{*cookie};
|
IoStatementState &io{*cookie};
|
||||||
if (!io.get_if<OutputStatementState>()) {
|
if (!io.get_if<OutputStatementState>()) {
|
||||||
io.GetIoErrorHandler().Crash(
|
io.GetIoErrorHandler().Crash(
|
||||||
"OutputReal32() called for a non-output I/O statement");
|
"OutputReal() called for a non-output I/O statement");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (auto edit{io.GetNextDataEdit()}) {
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IONAME(InputReal32)(Cookie cookie, float &x) {
|
bool IONAME(InputReal32)(Cookie cookie, float &x) {
|
||||||
IoStatementState &io{*cookie};
|
return InputReal<24, float>(cookie, x);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IONAME(InputReal64)(Cookie cookie, double &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};
|
IoStatementState &io{*cookie};
|
||||||
if (!io.get_if<InputStatementState>()) {
|
if (!io.get_if<InputStatementState>()) {
|
||||||
io.GetIoErrorHandler().Crash(
|
io.GetIoErrorHandler().Crash(
|
||||||
"InputReal64() called for a non-input I/O statement");
|
"InputComplex() called for a non-input I/O statement");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
for (int j{0}; j < 2; ++j) {
|
||||||
if (auto edit{io.GetNextDataEdit()}) {
|
if (auto edit{io.GetNextDataEdit()}) {
|
||||||
if (edit->descriptor == DataEdit::ListDirectedNullValue) {
|
if (edit->descriptor == DataEdit::ListDirectedNullValue) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return EditRealInput<53>(io, *edit, reinterpret_cast<void *>(&x));
|
if (!EditRealInput<PREC>(io, *edit, reinterpret_cast<void *>(&x[j]))) {
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IONAME(OutputComplex32)(Cookie cookie, float r, float z) {
|
bool IONAME(InputComplex32)(Cookie cookie, float x[2]) {
|
||||||
IoStatementState &io{*cookie};
|
return InputComplex<24, float>(cookie, x);
|
||||||
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(OutputComplex64)(Cookie cookie, double r, double z) {
|
bool IONAME(InputComplex64)(Cookie cookie, double x[2]) {
|
||||||
IoStatementState &io{*cookie};
|
return InputComplex<53, double>(cookie, x);
|
||||||
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(OutputAscii)(Cookie cookie, const char *x, std::size_t length) {
|
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(OutputReal64)(Cookie, double);
|
||||||
bool IONAME(InputReal64)(Cookie, double &);
|
bool IONAME(InputReal64)(Cookie, double &);
|
||||||
bool IONAME(OutputComplex32)(Cookie, float, float);
|
bool IONAME(OutputComplex32)(Cookie, float, float);
|
||||||
|
bool IONAME(InputComplex32)(Cookie, float[2]);
|
||||||
bool IONAME(OutputComplex64)(Cookie, double, double);
|
bool IONAME(OutputComplex64)(Cookie, double, double);
|
||||||
|
bool IONAME(InputComplex64)(Cookie, double[2]);
|
||||||
bool IONAME(OutputAscii)(Cookie, const char *, std::size_t);
|
bool IONAME(OutputAscii)(Cookie, const char *, std::size_t);
|
||||||
bool IONAME(InputAscii)(Cookie, char *, std::size_t);
|
bool IONAME(InputAscii)(Cookie, char *, std::size_t);
|
||||||
bool IONAME(OutputLogical)(Cookie, bool);
|
bool IONAME(OutputLogical)(Cookie, bool);
|
||||||
|
|
|
@ -509,6 +509,7 @@ ListDirectedStatementState<Direction::Input>::GetNextDataEdit(
|
||||||
} else if (realPart_) {
|
} else if (realPart_) {
|
||||||
realPart_ = false;
|
realPart_ = false;
|
||||||
imaginaryPart_ = true;
|
imaginaryPart_ = true;
|
||||||
|
edit.descriptor = DataEdit::ListDirectedImaginaryPart;
|
||||||
}
|
}
|
||||||
if (!ch) {
|
if (!ch) {
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
|
@ -574,6 +575,7 @@ ListDirectedStatementState<Direction::Input>::GetNextDataEdit(
|
||||||
if (!imaginaryPart_ && ch && *ch == '(') {
|
if (!imaginaryPart_ && ch && *ch == '(') {
|
||||||
realPart_ = true;
|
realPart_ = true;
|
||||||
io.HandleRelativePosition(1);
|
io.HandleRelativePosition(1);
|
||||||
|
edit.descriptor = DataEdit::ListDirectedRealPart;
|
||||||
}
|
}
|
||||||
return edit;
|
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) {
|
static void realTest(const char *format, double x, const char *expect) {
|
||||||
char buffer[800];
|
char buffer[800];
|
||||||
auto cookie{IONAME(BeginInternalFormattedOutput)(
|
auto cookie{IONAME(BeginInternalFormattedOutput)(
|
||||||
|
@ -444,5 +481,7 @@ int main() {
|
||||||
realInTest("(BZ,F18.0)", " 125 ", 0x4093880000000000); // 1250
|
realInTest("(BZ,F18.0)", " 125 ", 0x4093880000000000); // 1250
|
||||||
realInTest("(DC,F18.0)", " 12,5", 0x4029000000000000);
|
realInTest("(DC,F18.0)", " 12,5", 0x4029000000000000);
|
||||||
|
|
||||||
|
listInputTest();
|
||||||
|
|
||||||
return EndTests();
|
return EndTests();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue