[flang-commits] [flang] [Flang] add support for collapsed io calls for implicit do loops (PR #212646)

Jason Van Beusekom via flang-commits flang-commits at lists.llvm.org
Tue Sep 15 09:54:38 PDT 2026


================
@@ -701,6 +702,301 @@ static mlir::func::FuncOp getOutputFunc(mlir::Location loc,
                                                                    builder);
 }
 
+/// Return the evaluate expression of a non-implied-do io item, or nullptr if
+/// the item is itself an io-implied-do.
+static const Fortran::lower::SomeExpr *
+getIoItemLeafExpr(const Fortran::parser::OutputItem &item) {
+  if (const auto *parserExpr = std::get_if<Fortran::parser::Expr>(&item.u))
+    return Fortran::semantics::GetExpr(*parserExpr);
+  return nullptr;
+}
+static const Fortran::lower::SomeExpr *
+getIoItemLeafExpr(const Fortran::parser::InputItem &item) {
+  if (const auto *var = std::get_if<Fortran::parser::Variable>(&item.u))
+    return Fortran::semantics::GetExpr(*var);
+  return nullptr;
+}
+
+// CollectSymbols does not look through callee bodies, so this only
+// sees symbols the expression names directly (see NonSimpleCallFinder for the
+// call case).
+template <typename A, typename Pred>
+static bool ioAnyReferencedSymbol(const A &expr, Pred pred) {
+  for (const Fortran::semantics::SymbolRef &ref :
+       Fortran::evaluate::CollectSymbols(expr))
+    if (pred(ref->GetUltimate()))
+      return true;
+  return false;
+}
+
+template <typename A>
+static bool ioExprReferencesSymbol(const A &expr,
+                                   const Fortran::semantics::Symbol &sym) {
+  const Fortran::semantics::Symbol &ultimate = sym.GetUltimate();
+  return ioAnyReferencedSymbol(expr, [&](const Fortran::semantics::Symbol &s) {
+    return &s == &ultimate;
+  });
+}
+
+namespace {
+// Symbol collection does not look through callee bodies, so a non-SIMPLE
+// function hidden in a bound or retained subscript could read the io-implied-do
+// variable or the array being transferred.
+struct NonSimpleCallFinder
+    : public Fortran::evaluate::AnyTraverse<NonSimpleCallFinder, bool> {
+  using Base = Fortran::evaluate::AnyTraverse<NonSimpleCallFinder, bool>;
+  NonSimpleCallFinder() : Base{*this} {}
+  using Base::operator();
+  bool operator()(const Fortran::evaluate::ProcedureRef &call) const {
+    if (!call.proc().IsSimple())
+      return true;
+    return Base::operator()(call);
+  }
+};
+} // namespace
+
+// A bound or retained subscript is evaluated once for the collapsed section
+// rather than once per source-loop iteration, so it must not depend on the loop
+// variable, hide a non-SIMPLE call that could read it, or read a volatile.
+template <typename A>
+static bool
+ioExprUnsafeForSingleEvaluation(const A &expr,
+                                const Fortran::semantics::Symbol &loopSym) {
+  return ioExprReferencesSymbol(expr, loopSym) || NonSimpleCallFinder{}(expr) ||
+         ioAnyReferencedSymbol(expr, [](const Fortran::semantics::Symbol &s) {
+           return s.attrs().test(Fortran::semantics::Attr::VOLATILE);
+         });
+}
+
+/// Return true if \p symbol may share storage with another symbol via
+/// EQUIVALENCE, COMMON, POINTER/TARGET, ASSOCIATE, or Cray pointee.
+static bool
+ioSymbolMayBeStorageAssociated(const Fortran::semantics::Symbol &symbol) {
+  const Fortran::semantics::Symbol &ultimate = symbol.GetUltimate();
+  return Fortran::semantics::IsPointer(ultimate) ||
+         ultimate.attrs().test(Fortran::semantics::Attr::TARGET) ||
+         ultimate.test(Fortran::semantics::Symbol::Flag::CrayPointee) ||
+         Fortran::semantics::FindEquivalenceSet(ultimate) ||
+         Fortran::semantics::FindCommonBlockContaining(ultimate) ||
+         ultimate.detailsIf<Fortran::semantics::AssocEntityDetails>();
+}
+
+namespace {
+struct CollapsedImpliedDo {
+  Fortran::lower::SomeExpr section;
+  const Fortran::semantics::Symbol *loopSym;
+  Fortran::lower::SomeExpr loopLowerValue;
+  Fortran::lower::SomeExpr loopStepValue;
+};
+} // namespace
+
+/// Try to recognize a (single-level) io-implied-do as an equivalent contiguous
+/// array section. Returns the section expression on success, std::nullopt
+/// otherwise
+template <typename ImpliedDo>
+static std::optional<CollapsedImpliedDo>
+matchContiguousImpliedDo(Fortran::lower::AbstractConverter &converter,
----------------
Jason-Van-Beusekom wrote:

Handled in https://github.com/llvm/llvm-project/pull/212646/commits/1fd54993f0f7181bd29ea7288d8f537d0e5b48cb

https://github.com/llvm/llvm-project/pull/212646


More information about the flang-commits mailing list