[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