From 77d667b114bee344d1e0459839afe58f4af53089 Mon Sep 17 00:00:00 2001 From: Shao-Ce SUN Date: Wed, 29 Mar 2023 00:38:18 +0800 Subject: [PATCH] [flang][runtime] Support L editing of Logical I tested gfortran and flang(old). https://godbolt.org/z/c89foro4G Reviewed By: klausler Differential Revision: https://reviews.llvm.org/D146989 --- flang/docs/Extensions.md | 1 + flang/runtime/edit-output.cpp | 6 ++ flang/runtime/format-implementation.h | 3 +- flang/unittests/Runtime/CMakeLists.txt | 1 + flang/unittests/Runtime/LogicalFormatTest.cpp | 56 +++++++++++++++++++ 5 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 flang/unittests/Runtime/LogicalFormatTest.cpp diff --git a/flang/docs/Extensions.md b/flang/docs/Extensions.md index c49e5c80c0355..fbeada77d6443 100644 --- a/flang/docs/Extensions.md +++ b/flang/docs/Extensions.md @@ -112,6 +112,7 @@ end * Quad precision REAL literals with `Q` * `X` prefix/suffix as synonym for `Z` on hexadecimal literals * `B`, `O`, `Z`, and `X` accepted as suffixes as well as prefixes +* Support for using bare `L` in FORMAT statement * Triplets allowed in array constructors * `%LOC`, `%VAL`, and `%REF` * Leading comma allowed before I/O item list diff --git a/flang/runtime/edit-output.cpp b/flang/runtime/edit-output.cpp index 08a75822bacd4..0b31df766087c 100644 --- a/flang/runtime/edit-output.cpp +++ b/flang/runtime/edit-output.cpp @@ -139,6 +139,8 @@ bool EditIntegerOutput(IoStatementState &io, const DataEdit &edit, case 'Z': return EditBOZOutput<4>( io, edit, reinterpret_cast(&n), KIND); + case 'L': + return EditLogicalOutput(io, edit, *reinterpret_cast(&n)); case 'A': // legacy extension return EditCharacterOutput( io, edit, reinterpret_cast(&n), sizeof n); @@ -589,6 +591,8 @@ template bool RealOutputEditing::Edit(const DataEdit &edit) { common::BitsForBinaryPrecision(common::PrecisionOfRealKind(KIND)) >> 3); case 'G': return Edit(EditForGOutput(edit)); + case 'L': + return EditLogicalOutput(io_, edit, *reinterpret_cast(&x_)); case 'A': // legacy extension return EditCharacterOutput( io_, edit, reinterpret_cast(&x_), sizeof x_); @@ -712,6 +716,8 @@ bool EditCharacterOutput(IoStatementState &io, const DataEdit &edit, case 'Z': return EditBOZOutput<4>(io, edit, reinterpret_cast(x), sizeof(CHAR) * length); + case 'L': + return EditLogicalOutput(io, edit, *reinterpret_cast(x)); default: io.GetIoErrorHandler().SignalError(IostatErrorInFormat, "Data edit descriptor '%c' may not be used with a CHARACTER data item", diff --git a/flang/runtime/format-implementation.h b/flang/runtime/format-implementation.h index 89c700eaa4b2d..79063e2f9ebac 100644 --- a/flang/runtime/format-implementation.h +++ b/flang/runtime/format-implementation.h @@ -479,7 +479,8 @@ std::optional FormatControl::GetNextDataEdit( } } } - if (edit.descriptor == 'A') { // width is optional for A[w] + if (edit.descriptor == 'A' || edit.descriptor == 'L') { + // width is optional for A[w] or L[w] auto ch{PeekNext()}; if (ch >= '0' && ch <= '9') { edit.width = GetIntField(context); diff --git a/flang/unittests/Runtime/CMakeLists.txt b/flang/unittests/Runtime/CMakeLists.txt index 325eb5433f3a0..bba52706ea2d4 100644 --- a/flang/unittests/Runtime/CMakeLists.txt +++ b/flang/unittests/Runtime/CMakeLists.txt @@ -11,6 +11,7 @@ add_flang_unittest(FlangRuntimeTests Format.cpp Inquiry.cpp ListInputTest.cpp + LogicalFormatTest.cpp Matmul.cpp MatmulTranspose.cpp MiscIntrinsic.cpp diff --git a/flang/unittests/Runtime/LogicalFormatTest.cpp b/flang/unittests/Runtime/LogicalFormatTest.cpp new file mode 100644 index 0000000000000..a2c19d1e1ca94 --- /dev/null +++ b/flang/unittests/Runtime/LogicalFormatTest.cpp @@ -0,0 +1,56 @@ +//===-- flang/unittests/Runtime/LogicalFormatTest.cpp -----------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "CrashHandlerFixture.h" +#include "flang/Runtime/descriptor.h" +#include "flang/Runtime/io-api.h" +#include +#include +#include +#include +#include + +using namespace Fortran::runtime; +using namespace Fortran::runtime::io; + +TEST(IOApiTests, LogicalFormatTest) { + static constexpr int bufferSize{29}; + char buffer[bufferSize]; + + // Create format for all types and values to be written + const char *format{"(L,L3,I3,L2,L2,I3,L2,A3,L2,L,F4.1,L2)"}; + auto cookie{IONAME(BeginInternalFormattedOutput)( + buffer, bufferSize, format, std::strlen(format))}; + + // Write string, integer, and logical values to buffer + IONAME(OutputLogical)(cookie, true); + IONAME(OutputLogical)(cookie, false); + IONAME(OutputInteger64)(cookie, 6); + IONAME(OutputInteger32)(cookie, 22); + IONAME(OutputInteger32)(cookie, 0); + IONAME(OutputInteger32)(cookie, -2); + IONAME(OutputCharacter)(cookie, "ABC", 3); + IONAME(OutputCharacter)(cookie, "AB", 2); + IONAME(OutputReal64)(cookie, 0.0); + IONAME(OutputCharacter)(cookie, "", 0); + IONAME(OutputReal32)(cookie, 2.3); + IONAME(OutputReal32)(cookie, 2.3); + + // Ensure IO succeeded + auto status{IONAME(EndIoStatement)(cookie)}; + ASSERT_EQ(status, 0) << "logical format: '" << format << "' failed, status " + << static_cast(status); + + // Ensure final buffer matches expected string output + static const std::string expect{"T F 6 T F -2 T AB FF 2.3 T"}; + + // expect.size() == bufferSize - 1 + std::string bufferStr = std::string(buffer, bufferSize - 1); + ASSERT_TRUE(expect == bufferStr) + << "Expected '" << expect << "', got '" << bufferStr << "'"; +}