From 840b84b86cd4ff448733eb57621c442837cd75ee Mon Sep 17 00:00:00 2001 From: Peter Klausler Date: Thu, 25 Sep 2025 10:33:39 -0700 Subject: [PATCH] [flang][runtime] Expand IOTYPE and V_LIST The IOTYPE and V_LIST dummy arguments to a defined formatted I/O subroutine are extracted from a DT edit descriptor in a FORMAT. They are currently stored in the DataEdit structure, and their maximum sizes are rather small since DataEdits are sometimes returned or passed by value. This patch moves their storage into the FormattedIoStatementState structure and enlarges them a bit. Fixes https://github.com/llvm/llvm-project/issues/154954. --- .../include/flang-rt/runtime/format-implementation.h | 4 ++-- flang-rt/include/flang-rt/runtime/format.h | 3 +-- flang-rt/include/flang-rt/runtime/io-stmt.h | 10 ++++++++-- flang-rt/lib/runtime/descriptor-io.cpp | 7 ++++--- flang-rt/unittests/Runtime/Format.cpp | 2 +- 5 files changed, 16 insertions(+), 10 deletions(-) diff --git a/flang-rt/include/flang-rt/runtime/format-implementation.h b/flang-rt/include/flang-rt/runtime/format-implementation.h index de06524de32d3..46134146f5c13 100644 --- a/flang-rt/include/flang-rt/runtime/format-implementation.h +++ b/flang-rt/include/flang-rt/runtime/format-implementation.h @@ -532,7 +532,7 @@ RT_API_ATTRS common::optional FormatControl::GetNextDataEdit( ReportBadFormat(context, "Excessive DT'iotype' in FORMAT", start); return common::nullopt; } - edit.ioType[edit.ioTypeChars++] = ch; + context.ioType[edit.ioTypeChars++] = ch; if (ch == quote) { ++offset_; } @@ -556,7 +556,7 @@ RT_API_ATTRS common::optional FormatControl::GetNextDataEdit( ReportBadFormat(context, "Excessive DT(v_list) in FORMAT", start); return common::nullopt; } - edit.vList[edit.vListEntries++] = n; + context.vList[edit.vListEntries++] = n; auto ch{static_cast(GetNextChar(context))}; if (ch != ',') { ok = ch == ')'; diff --git a/flang-rt/include/flang-rt/runtime/format.h b/flang-rt/include/flang-rt/runtime/format.h index 34e33edae546d..79a7dd713b1a1 100644 --- a/flang-rt/include/flang-rt/runtime/format.h +++ b/flang-rt/include/flang-rt/runtime/format.h @@ -86,12 +86,11 @@ struct DataEdit { // defined I/O data edit descriptor RT_OFFLOAD_VAR_GROUP_BEGIN static constexpr std::size_t maxIoTypeChars{32}; - static constexpr std::size_t maxVListEntries{4}; + static constexpr std::size_t maxVListEntries{16}; RT_OFFLOAD_VAR_GROUP_END std::uint8_t ioTypeChars{0}; std::uint8_t vListEntries{0}; char ioType[maxIoTypeChars]; - int vList[maxVListEntries]; }; // Generates a sequence of DataEdits from a FORMAT statement or diff --git a/flang-rt/include/flang-rt/runtime/io-stmt.h b/flang-rt/include/flang-rt/runtime/io-stmt.h index 1c4f06c0a7082..21f152e082a21 100644 --- a/flang-rt/include/flang-rt/runtime/io-stmt.h +++ b/flang-rt/include/flang-rt/runtime/io-stmt.h @@ -61,8 +61,14 @@ using IoDirectionState = std::conditional_t; // Common state for all kinds of formatted I/O -template class FormattedIoStatementState {}; -template <> class FormattedIoStatementState { +struct DefinedIoArgs { + char ioType[DataEdit::maxIoTypeChars]; // IOTYPE string + int vList[DataEdit::maxVListEntries]; // V_LIST(:) values +}; +template +class FormattedIoStatementState : public DefinedIoArgs {}; +template <> +class FormattedIoStatementState : public DefinedIoArgs { public: RT_API_ATTRS std::size_t GetEditDescriptorChars() const; RT_API_ATTRS void GotChar(int); diff --git a/flang-rt/lib/runtime/descriptor-io.cpp b/flang-rt/lib/runtime/descriptor-io.cpp index e00072510aff7..4483906ecb508 100644 --- a/flang-rt/lib/runtime/descriptor-io.cpp +++ b/flang-rt/lib/runtime/descriptor-io.cpp @@ -62,10 +62,11 @@ static RT_API_ATTRS common::optional DefinedFormattedIo( : *io.GetNextDataEdit(1)}; char ioType[2 + edit.maxIoTypeChars]; auto ioTypeLen{std::size_t{2} /*"DT"*/ + edit.ioTypeChars}; + auto &definedIoArgs{*io.get_if()}; if (edit.descriptor == DataEdit::DefinedDerivedType) { ioType[0] = 'D'; ioType[1] = 'T'; - runtime::memcpy(ioType + 2, edit.ioType, edit.ioTypeChars); + runtime::memcpy(ioType + 2, definedIoArgs.ioType, edit.ioTypeChars); } else { runtime::strcpy( ioType, io.mutableModes().inNamelist ? "NAMELIST" : "LISTDIRECTED"); @@ -79,7 +80,7 @@ static RT_API_ATTRS common::optional DefinedFormattedIo( if (integer8) { // Convert v_list values to INTEGER(8) for (int j{0}; j < edit.vListEntries; ++j) { - vList64[j] = edit.vList[j]; + vList64[j] = definedIoArgs.vList[j]; } vListDesc.Establish( TypeCategory::Integer, sizeof(std::int64_t), nullptr, 1); @@ -89,7 +90,7 @@ static RT_API_ATTRS common::optional DefinedFormattedIo( static_cast(sizeof(std::int64_t))); } else { vListDesc.Establish(TypeCategory::Integer, sizeof(int), nullptr, 1); - vListDesc.set_base_addr(edit.vList); + vListDesc.set_base_addr(definedIoArgs.vList); vListDesc.GetDimension(0).SetBounds(1, edit.vListEntries); vListDesc.GetDimension(0).SetByteStride( static_cast(sizeof(int))); diff --git a/flang-rt/unittests/Runtime/Format.cpp b/flang-rt/unittests/Runtime/Format.cpp index fe7403f26700b..cd52dc8c54ed5 100644 --- a/flang-rt/unittests/Runtime/Format.cpp +++ b/flang-rt/unittests/Runtime/Format.cpp @@ -22,7 +22,7 @@ using namespace std::literals::string_literals; using ResultsTy = std::vector; // A test harness context for testing FormatControl -class TestFormatContext : public IoErrorHandler { +class TestFormatContext : public IoErrorHandler, public DefinedIoArgs { public: using CharType = char; TestFormatContext() : IoErrorHandler{"format.cpp", 1} {}