[flang-commits] [flang] [flang][MIF] Adding common features related to coarray (PR #215576)

Jean-Didier PAILLEUX via flang-commits flang-commits at lists.llvm.org
Wed Aug 12 00:17:11 PDT 2026


https://github.com/JDPailleux updated https://github.com/llvm/llvm-project/pull/215576

>From 2dedde75c5859568eaf8618ab50062275e0f2526 Mon Sep 17 00:00:00 2001
From: Jean-Didier Pailleux <jean-didier.pailleux at sipearl.com>
Date: Thu, 16 Jul 2026 11:49:38 +0200
Subject: [PATCH 1/4] [flang] Lower CoarrayRef to hlfir.designate

---
 flang/lib/Lower/ConvertExprToHLFIR.cpp   | 112 ++++++++++++++++++++++-
 flang/test/Lower/MIF/coarray-declare.f90 |  18 ++++
 2 files changed, 127 insertions(+), 3 deletions(-)
 create mode 100644 flang/test/Lower/MIF/coarray-declare.f90

diff --git a/flang/lib/Lower/ConvertExprToHLFIR.cpp b/flang/lib/Lower/ConvertExprToHLFIR.cpp
index 59ef7143914b2..50becf025441a 100644
--- a/flang/lib/Lower/ConvertExprToHLFIR.cpp
+++ b/flang/lib/Lower/ConvertExprToHLFIR.cpp
@@ -402,11 +402,117 @@ class HlfirDesignatorBuilder {
 
   fir::FortranVariableOpInterface
   gen(const Fortran::evaluate::CoarrayRef &coarrayRef) {
-    TODO(getLoc(), "coarray: lowering a reference to a coarray object");
+    PartInfo partInfo;
+    mlir::Type resultType = visit(coarrayRef, partInfo);
+    return genDesignate(resultType, partInfo, coarrayRef);
   }
 
-  mlir::Type visit(const Fortran::evaluate::CoarrayRef &, PartInfo &) {
-    TODO(getLoc(), "coarray: lowering a reference to a coarray object");
+  mlir::Type visit(const Fortran::evaluate::CoarrayRef &coarrayRef,
+                   PartInfo &partInfo) {
+    // Coarray is a data entity with corank > 0 that must be scalar
+    // or array.
+    mlir::Type baseType = visit(coarrayRef.base().GetLastSymbol(), partInfo);
+    if (auto seqType = mlir::dyn_cast<fir::SequenceType>(baseType)) {
+      fir::FirOpBuilder &builder = getBuilder();
+      mlir::Location loc = getLoc();
+      mlir::Type idxTy = builder.getIndexType();
+      llvm::SmallVector<std::pair<mlir::Value, mlir::Value>> bounds;
+      auto getBaseBounds = [&](unsigned i) {
+        if (bounds.empty()) {
+          bounds = hlfir::genBounds(loc, builder, partInfo.base.value());
+          assert(!bounds.empty() &&
+                 "failed to compute implicit array section bounds");
+        }
+        return bounds[i];
+      };
+
+      auto frontEndResultShape = Fortran::evaluate::GetShape(
+          converter.getFoldingContext(), coarrayRef);
+      auto tryGettingExtentFromFrontEnd = [&](unsigned dim)
+          -> std::pair<mlir::Value, fir::SequenceType::Extent> {
+        // Use constant extent if possible. The main advantage to do this now
+        // is to get the best FIR array types as possible while lowering.
+        if (frontEndResultShape)
+          if (auto maybeI64 =
+                  Fortran::evaluate::ToInt64(frontEndResultShape->at(dim)))
+            return {builder.createIntegerConstant(loc, idxTy, *maybeI64),
+                    *maybeI64};
+        return {mlir::Value{}, fir::SequenceType::getUnknownExtent()};
+      };
+
+      llvm::SmallVector<mlir::Value> resultExtents;
+      fir::SequenceType::Shape resultTypeShape;
+      bool sawVectorSubscripts = false;
+      if (auto *arrayRef{
+              std::get_if<Fortran::evaluate::ArrayRef>(&coarrayRef.base().u)}) {
+        for (auto subscript : llvm::enumerate(arrayRef->subscript())) {
+          if (const auto *triplet = std::get_if<Fortran::evaluate::Triplet>(
+                  &subscript.value().u)) {
+            mlir::Value lb, ub;
+            if (const auto &lbExpr = triplet->lower())
+              lb = genSubscript(*lbExpr);
+            else
+              lb = getBaseBounds(subscript.index()).first;
+            if (const auto &ubExpr = triplet->upper())
+              ub = genSubscript(*ubExpr);
+            else
+              ub = getBaseBounds(subscript.index()).second;
+            lb = builder.createConvert(loc, idxTy, lb);
+            ub = builder.createConvert(loc, idxTy, ub);
+            mlir::Value stride = genSubscript(triplet->stride());
+            stride = builder.createConvert(loc, idxTy, stride);
+            auto [extentValue, shapeExtent] =
+                tryGettingExtentFromFrontEnd(resultExtents.size());
+            resultTypeShape.push_back(shapeExtent);
+            if (!extentValue)
+              extentValue =
+                  builder.genExtentFromTriplet(loc, lb, ub, stride, idxTy);
+            resultExtents.push_back(extentValue);
+            partInfo.subscripts.emplace_back(
+                hlfir::DesignateOp::Triplet{lb, ub, stride});
+          } else {
+            const auto &expr =
+                std::get<Fortran::evaluate::IndirectSubscriptIntegerExpr>(
+                    subscript.value().u)
+                    .value();
+            hlfir::Entity subscript = genSubscript(expr);
+            partInfo.subscripts.push_back(subscript);
+            if (expr.Rank() > 0) {
+              sawVectorSubscripts = true;
+              auto [extentValue, shapeExtent] =
+                  tryGettingExtentFromFrontEnd(resultExtents.size());
+              resultTypeShape.push_back(shapeExtent);
+              if (!extentValue)
+                extentValue =
+                    hlfir::genExtent(loc, builder, subscript, /*dim=*/0);
+              resultExtents.push_back(extentValue);
+            }
+          }
+        }
+      }
+      assert(resultExtents.size() == resultTypeShape.size() &&
+             "inconsistent hlfir.designate shape");
+
+      // For vector subscripts, create an hlfir.elemental_addr and continue
+      // lowering the designator inside it as if it was addressing an element of
+      // the vector subscripts.
+      if (sawVectorSubscripts)
+        return createVectorSubscriptElementAddrOp(partInfo, baseType,
+                                                  resultExtents);
+
+      mlir::Type resultType = seqType.getEleTy();
+      if (!resultTypeShape.empty()) {
+        // Ranked array section. The result shape comes from the array section
+        // subscripts.
+        resultType = fir::SequenceType::get(resultTypeShape, resultType);
+        assert(!partInfo.resultShape &&
+               "Fortran designator can only have one ranked part");
+        partInfo.resultShape = builder.genShape(loc, resultExtents);
+      }
+      return resultType;
+    } else {
+      return baseType;
+    }
   }
 
   fir::FortranVariableOpInterface
diff --git a/flang/test/Lower/MIF/coarray-declare.f90 b/flang/test/Lower/MIF/coarray-declare.f90
new file mode 100644
index 0000000000000..881a3e135b757
--- /dev/null
+++ b/flang/test/Lower/MIF/coarray-declare.f90
@@ -0,0 +1,18 @@
+! This test is used to demonstrate that coindexed expressions can be lowered, but it does not in any way validate the assignment `val = a[2]`.
+! This test is intended to be removed or modified once PUT/GET operations on coarrays have been supported.
+
+! RUN: %flang_fc1 -emit-hlfir -fcoarray %s -o - | FileCheck %s
+
+program main
+  integer :: a[*]
+  integer :: val
+  
+  val = a[2]
+end program
+    
+!CHECK: %[[VAL_1:.*]] = fir.address_of(@_QFEa) : !fir.ref<i32>
+!CHECK: %[[VAL_2:.*]]:2 = hlfir.declare %[[VAL_1]] {uniq_name = "_QFEa"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+!CHECK: %[[VAL_3:.*]] = fir.alloca i32 {bindc_name = "val", uniq_name = "_QFEval"}
+!CHECK: %[[VAL_4:.*]]:2 = hlfir.declare %[[VAL_3]] {uniq_name = "_QFEval"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+!CHECK: %[[VAL_5:.*]] = hlfir.designate %[[VAL_2]]#0 : (!fir.ref<i32>) -> !fir.ref<i32>
+

>From 94ade9ef13641e1691f5213ccd5b61b47bfabcef Mon Sep 17 00:00:00 2001
From: Jean-Didier Pailleux <jean-didier.pailleux at sipearl.com>
Date: Tue, 11 Aug 2026 16:26:28 +0200
Subject: [PATCH 2/4] [flang][MIF] Add 2 commons functions to generate
 cosubscipts and initial image_index

---
 flang/include/flang/Lower/MultiImageFortran.h |  4 ++
 flang/lib/Lower/MultiImageFortran.cpp         | 28 +++++++++
 .../Optimizer/Transforms/MIFOpConversion.cpp  | 60 +++++++++++++++++++
 3 files changed, 92 insertions(+)

diff --git a/flang/include/flang/Lower/MultiImageFortran.h b/flang/include/flang/Lower/MultiImageFortran.h
index c9b9e9f17cf39..1f247ee46c3a9 100644
--- a/flang/include/flang/Lower/MultiImageFortran.h
+++ b/flang/include/flang/Lower/MultiImageFortran.h
@@ -63,6 +63,10 @@ void genFormTeamStatement(AbstractConverter &, pft::Evaluation &eval,
 // COARRAY utils
 //===----------------------------------------------------------------------===//
 
+mlir::SmallVector<mlir::Value>
+getCosubscripts(AbstractConverter &converter, mlir::Location loc,
+                const evaluate::CoarrayRef &expr);
+
 mlir::Value genLowerCoBounds(AbstractConverter &converter, mlir::Location loc,
                              const semantics::Symbol &sym);
 
diff --git a/flang/lib/Lower/MultiImageFortran.cpp b/flang/lib/Lower/MultiImageFortran.cpp
index 12149a537ec29..b2a3d662fc8e7 100644
--- a/flang/lib/Lower/MultiImageFortran.cpp
+++ b/flang/lib/Lower/MultiImageFortran.cpp
@@ -263,6 +263,34 @@ void Fortran::lower::genFormTeamStatement(
 // COARRAY utils
 //===----------------------------------------------------------------------===//
 
+/// Generates a vector of cosubscripts from CoarrayRef
+mlir::SmallVector<mlir::Value>
+Fortran::lower::getCosubscripts(Fortran::lower::AbstractConverter &converter,
+                                mlir::Location loc,
+                                const Fortran::evaluate::CoarrayRef &expr) {
+  fir::FirOpBuilder &builder = converter.getFirOpBuilder();
+  Fortran::lower::StatementContext stmtCtx;
+  mlir::SmallVector<mlir::Value> cosubscripts;
+
+  // Creation of the cosubscripts vector
+  mlir::Type i64Ty = builder.getI64Type();
+  unsigned corank = expr.cosubscript().size();
+  for (unsigned dim = 0; dim < corank; ++dim) {
+    auto image = ToInt64(expr.cosubscript()[dim]);
+    mlir::Value idx;
+    if (image.has_value())
+      idx = builder.createIntegerConstant(loc, i64Ty, image.value());
+    else {
+      auto s = ignoreEvConvert(expr.cosubscript()[dim]);
+      idx = builder.createConvert(
+          loc, i64Ty, fir::getBase(converter.genExprValue(loc, s, stmtCtx)));
+    }
+
+    cosubscripts.push_back(idx);
+  }
+  return cosubscripts;
+}
+
 mlir::Value
 Fortran::lower::genLowerCoBounds(Fortran::lower::AbstractConverter &converter,
                                  mlir::Location loc,
diff --git a/flang/lib/Optimizer/Transforms/MIFOpConversion.cpp b/flang/lib/Optimizer/Transforms/MIFOpConversion.cpp
index fb3c794c0cd9e..7f7c031478c56 100644
--- a/flang/lib/Optimizer/Transforms/MIFOpConversion.cpp
+++ b/flang/lib/Optimizer/Transforms/MIFOpConversion.cpp
@@ -346,6 +346,66 @@ mlir::Value genTerminationOperationWrapper(fir::FirOpBuilder &builder,
   return fir::AddrOfOp::create(builder, loc, funcType, symbolRef);
 }
 
+// Generates the image index relative to the initial team, regardless of which
+// team is selected. Generates a call to the `prif_initial_team_index` function
+// (analogous to `prif_image_index`) if `cosubcripts` contains at least one
+// value; otherwise, it generates a call to `prif_this_image_no_coarray` without
+// the `team` argument.
+[[maybe_unused]] static mlir::Value
+getInitialTeamIndex(fir::FirOpBuilder &builder, mlir::Location loc,
+                    mlir::Value coarrayHandle,
+                    llvm::SmallVector<mlir::Value> cosubscripts) {
+  mlir::Type boxTy = fir::BoxType::get(builder.getNoneType());
+  mlir::Type i32Ty = builder.getI32Type();
+  mlir::Type i64Ty = builder.getI64Type();
+  mlir::Type boxArrTy = genBoxedSequenceType(i64Ty);
+  mlir::Value index = builder.createTemporary(loc, i32Ty);
+
+  // If there are no subscripts, the current image index is used.
+  if (cosubscripts.size() == 0) {
+    mlir::FunctionType ftype = mlir::FunctionType::get(
+        builder.getContext(),
+        /*inputs*/ {boxTy, builder.getRefType(i32Ty)}, /*results*/ {});
+    mlir::Value teamArg = fir::AbsentOp::create(builder, loc, boxTy);
+    mlir::func::FuncOp funcOp = builder.createFunction(
+        loc, getPRIFProcName("this_image_no_coarray"), ftype);
+    llvm::SmallVector<mlir::Value> args =
+        fir::runtime::createArguments(builder, loc, ftype, teamArg, index);
+    fir::CallOp::create(builder, loc, funcOp, args);
+    return index;
+  }
+
+  mlir::FunctionType ftype = mlir::FunctionType::get(
+      builder.getContext(),
+      /*inputs*/
+      {boxTy, boxArrTy, builder.getRefType(i32Ty), builder.getRefType(i32Ty)},
+      /*results*/ {});
+  mlir::func::FuncOp funcOp =
+      builder.createFunction(loc, getPRIFProcName("initial_team_index"), ftype);
+
+  // Creation of sub
+  unsigned corank = cosubscripts.size();
+  mlir::Type indexType = builder.getIndexType();
+  mlir::Type arrayType = fir::SequenceType::get(
+      {static_cast<fir::SequenceType::Extent>(corank)}, i64Ty);
+  mlir::Value sub = builder.createTemporary(loc, arrayType);
+  mlir::Type addrType = builder.getRefType(i64Ty);
+  for (unsigned i = 0; i < corank; ++i) {
+    mlir::Value cs = builder.createConvert(loc, i64Ty, cosubscripts[i]);
+    auto index = builder.createIntegerConstant(loc, indexType, i);
+    auto addr = fir::CoordinateOp::create(builder, loc, addrType, sub, index);
+    fir::StoreOp::create(builder, loc, cs, addr);
+  }
+  sub = builder.createBox(loc, sub);
+
+  mlir::Value stat =
+      fir::AbsentOp::create(builder, loc, getPRIFStatType(builder));
+  llvm::SmallVector<mlir::Value> args = fir::runtime::createArguments(
+      builder, loc, ftype, coarrayHandle, sub, index, stat);
+  fir::CallOp::create(builder, loc, funcOp, args);
+  return index;
+}
+
 /// Convert mif.init operation to runtime call of 'prif_init'
 struct MIFInitOpConversion : public mlir::OpRewritePattern<mif::InitOp> {
   using OpRewritePattern::OpRewritePattern;

>From 02db7ca6c64e41603accc8fb0760f04ba1c43470 Mon Sep 17 00:00:00 2001
From: Jean-Didier PAILLEUX <jean-di.pailleux at outlook.com>
Date: Wed, 12 Aug 2026 09:16:12 +0200
Subject: [PATCH 3/4] Update flang/lib/Lower/MultiImageFortran.cpp

Co-authored-by: Dan Bonachea <dobonachea at lbl.gov>
---
 flang/lib/Lower/MultiImageFortran.cpp | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/flang/lib/Lower/MultiImageFortran.cpp b/flang/lib/Lower/MultiImageFortran.cpp
index b2a3d662fc8e7..931bc5e66b3cf 100644
--- a/flang/lib/Lower/MultiImageFortran.cpp
+++ b/flang/lib/Lower/MultiImageFortran.cpp
@@ -276,10 +276,10 @@ Fortran::lower::getCosubscripts(Fortran::lower::AbstractConverter &converter,
   mlir::Type i64Ty = builder.getI64Type();
   unsigned corank = expr.cosubscript().size();
   for (unsigned dim = 0; dim < corank; ++dim) {
-    auto image = ToInt64(expr.cosubscript()[dim]);
+    auto cosub = ToInt64(expr.cosubscript()[dim]);
     mlir::Value idx;
-    if (image.has_value())
-      idx = builder.createIntegerConstant(loc, i64Ty, image.value());
+    if (cosub.has_value())
+      idx = builder.createIntegerConstant(loc, i64Ty, cosub.value());
     else {
       auto s = ignoreEvConvert(expr.cosubscript()[dim]);
       idx = builder.createConvert(

>From 8edf4119db2f91bd6a0bd374e69a0726f65dddc0 Mon Sep 17 00:00:00 2001
From: Jean-Didier PAILLEUX <jean-di.pailleux at outlook.com>
Date: Wed, 12 Aug 2026 09:17:00 +0200
Subject: [PATCH 4/4] Update flang/lib/Optimizer/Transforms/MIFOpConversion.cpp

Co-authored-by: Dan Bonachea <dobonachea at lbl.gov>
---
 flang/lib/Optimizer/Transforms/MIFOpConversion.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/flang/lib/Optimizer/Transforms/MIFOpConversion.cpp b/flang/lib/Optimizer/Transforms/MIFOpConversion.cpp
index 7f7c031478c56..72d9a2106642e 100644
--- a/flang/lib/Optimizer/Transforms/MIFOpConversion.cpp
+++ b/flang/lib/Optimizer/Transforms/MIFOpConversion.cpp
@@ -392,8 +392,8 @@ getInitialTeamIndex(fir::FirOpBuilder &builder, mlir::Location loc,
   mlir::Type addrType = builder.getRefType(i64Ty);
   for (unsigned i = 0; i < corank; ++i) {
     mlir::Value cs = builder.createConvert(loc, i64Ty, cosubscripts[i]);
-    auto index = builder.createIntegerConstant(loc, indexType, i);
-    auto addr = fir::CoordinateOp::create(builder, loc, addrType, sub, index);
+    auto cs_index = builder.createIntegerConstant(loc, indexType, i);
+    auto addr = fir::CoordinateOp::create(builder, loc, addrType, sub, cs_index);
     fir::StoreOp::create(builder, loc, cs, addr);
   }
   sub = builder.createBox(loc, sub);



More information about the flang-commits mailing list