[flang-commits] [flang] 5595710 - [Flang][MIF] Allocation of NON-ALLOCATABLE SAVE coarray (#205847)

via flang-commits flang-commits at lists.llvm.org
Mon Jul 13 05:39:12 PDT 2026


Author: Jean-Didier PAILLEUX
Date: 2026-07-13T14:39:06+02:00
New Revision: 5595710093f7f8b9cdb0ff4f8d7400e58bde09b2

URL: https://github.com/llvm/llvm-project/commit/5595710093f7f8b9cdb0ff4f8d7400e58bde09b2
DIFF: https://github.com/llvm/llvm-project/commit/5595710093f7f8b9cdb0ff4f8d7400e58bde09b2.diff

LOG: [Flang][MIF] Allocation of NON-ALLOCATABLE SAVE coarray (#205847)

The goal of this PR is to add support for allocating NON-allocatable
coarrays that are not in the `Main` program.
All allocations will be performed in a function called
`__mif_save_coarrays_allocate`. If this function exists, then
LLVM::GlobalCtors is created (or modified).
The initialization of the MIF with `mif.init` is moved too in a
GlobalCtors with a priority of 0 to ensure that the initialization takes
place before any MIF allocations.

---------

Co-authored-by: Dan Bonachea <dobonachea at lbl.gov>

Added: 
    flang/lib/Optimizer/Transforms/EmitMIFGlobalCtors.cpp

Modified: 
    flang/include/flang/Lower/MultiImageFortran.h
    flang/include/flang/Optimizer/Builder/MIFCommon.h
    flang/include/flang/Optimizer/Dialect/MIF/MIFOps.td
    flang/include/flang/Optimizer/Transforms/Passes.td
    flang/lib/Lower/Bridge.cpp
    flang/lib/Lower/ConvertVariable.cpp
    flang/lib/Lower/MultiImageFortran.cpp
    flang/lib/Optimizer/Builder/MIFCommon.cpp
    flang/lib/Optimizer/Passes/Pipelines.cpp
    flang/lib/Optimizer/Transforms/CMakeLists.txt
    flang/test/Fir/basic-program.fir
    flang/test/Lower/MIF/coarray_allocation4.f90
    flang/test/Lower/MIF/coarray_allocation5.f90

Removed: 
    


################################################################################
diff  --git a/flang/include/flang/Lower/MultiImageFortran.h b/flang/include/flang/Lower/MultiImageFortran.h
index 002f156c807f2..c9b9e9f17cf39 100644
--- a/flang/include/flang/Lower/MultiImageFortran.h
+++ b/flang/include/flang/Lower/MultiImageFortran.h
@@ -76,6 +76,11 @@ mlir::Value genAllocateCoarray(
         std::nullopt,
     mlir::Value errMsg = {}, bool hasStat = false);
 
+void genAllocateNonAllocatableSaveCoarray(AbstractConverter &converter,
+                                          mlir::Location loc,
+                                          const semantics::Symbol &sym,
+                                          mlir::Value addr);
+
 //===----------------------------------------------------------------------===//
 // COARRAY expressions
 //===----------------------------------------------------------------------===//

diff  --git a/flang/include/flang/Optimizer/Builder/MIFCommon.h b/flang/include/flang/Optimizer/Builder/MIFCommon.h
index 91b8a037e2801..8c986dee0d179 100644
--- a/flang/include/flang/Optimizer/Builder/MIFCommon.h
+++ b/flang/include/flang/Optimizer/Builder/MIFCommon.h
@@ -13,6 +13,8 @@
 #include "flang/Optimizer/Dialect/MIF/MIFOps.h"
 
 static constexpr llvm::StringRef coarrayHandleSuffix = "_coarray_handle";
+static constexpr llvm::StringRef mifSaveCoarraysAllocName =
+    "__mif_save_coarrays_allocate";
 
 namespace mif {
 
@@ -22,6 +24,10 @@ mlir::Value genImageIndex(fir::FirOpBuilder &, mlir::Location loc,
                           mlir::Value coarray, mlir::Value sub,
                           mlir::Value team);
 
+mlir::func::FuncOp getOrCreateInitFunc(fir::FirOpBuilder &builder,
+                                       mlir::ModuleOp mod,
+                                       llvm::StringRef name);
+
 } // namespace mif
 
 #endif // FORTRAN_OPTIMIZER_TRANSFORMS_MIFCOMMON_H_

diff  --git a/flang/include/flang/Optimizer/Dialect/MIF/MIFOps.td b/flang/include/flang/Optimizer/Dialect/MIF/MIFOps.td
index 4acbeec47eb2e..337a9eab0b087 100644
--- a/flang/include/flang/Optimizer/Dialect/MIF/MIFOps.td
+++ b/flang/include/flang/Optimizer/Dialect/MIF/MIFOps.td
@@ -32,7 +32,12 @@ class region_Op<string mnemonic, list<Trait> traits = []>
 
 def mif_InitOp : mif_Op<"init", []> {
   let summary = "Initialize the parallel environment";
-  let description = [{This operation will initialize the parallel environment}];
+  let description = [{
+    This operation will initialize the parallel environment and shall be called
+    prior to any other MIF operations.
+    Any second or subsequent call to mif.init is guaranteed to return 
+    immediately with no effect.
+  }];
 
   let results = (outs I32:$stat);
   let assemblyFormat = "`->` type($stat) attr-dict";

diff  --git a/flang/include/flang/Optimizer/Transforms/Passes.td b/flang/include/flang/Optimizer/Transforms/Passes.td
index 4a042926b7a75..482260f26751d 100644
--- a/flang/include/flang/Optimizer/Transforms/Passes.td
+++ b/flang/include/flang/Optimizer/Transforms/Passes.td
@@ -691,6 +691,11 @@ def MIFOpConversion : Pass<"mif-convert", "mlir::ModuleOp"> {
                            "mlir::cf::ControlFlowDialect", "mlir::DLTIDialect"];
 }
 
+def EmitMIFGlobalCtors : Pass<"emit-mif-global-ctors", "mlir::ModuleOp"> {
+  let summary = "Generate GlobalCtorOp to init MIF and allocate coarrays.";
+  let dependentDialects = ["fir::FIROpsDialect", "mlir::LLVM::LLVMDialect"];
+}
+
 def LoopInvariantCodeMotion : Pass<"flang-licm", "::mlir::func::FuncOp"> {
   let summary = "Hoist invariants from loops";
   let description = [{

diff  --git a/flang/lib/Lower/Bridge.cpp b/flang/lib/Lower/Bridge.cpp
index 8658a6fb29a44..e2c895351c977 100644
--- a/flang/lib/Lower/Bridge.cpp
+++ b/flang/lib/Lower/Bridge.cpp
@@ -6634,15 +6634,6 @@ class FirConverter : public Fortran::lower::AbstractConverter {
         if (sym.name() == "numeric_storage_size" && owner.IsModule() &&
             DEREF(owner.symbol()).name() == "iso_fortran_env")
           continue;
-
-        if (Fortran::evaluate::IsCoarray(sym) &&
-            !Fortran::semantics::IsAllocatable(sym) &&
-            Fortran::semantics::IsSaved(sym)) {
-          mlir::Location loc = toLocation();
-          TODO(
-              loc,
-              "coarray: non-ALLOCATABLE SAVE coarray outside the main program");
-        }
       }
       Fortran::lower::defineModuleVariable(*this, var);
     }

diff  --git a/flang/lib/Lower/ConvertVariable.cpp b/flang/lib/Lower/ConvertVariable.cpp
index ae11a9230d1b0..f971feb0f01df 100644
--- a/flang/lib/Lower/ConvertVariable.cpp
+++ b/flang/lib/Lower/ConvertVariable.cpp
@@ -698,10 +698,15 @@ static void instantiateGlobal(Fortran::lower::AbstractConverter &converter,
   mlir::StringAttr linkage = getLinkageAttribute(converter, var);
   fir::GlobalOp global;
 
-  if (Fortran::evaluate::IsCoarray(sym))
+  if (Fortran::evaluate::IsCoarray(sym)) {
     if (hasFinalization(sym) || hasAllocatableDirectComponent(sym))
       TODO(loc, "coarray: coarray with an allocatable direct component and/or "
                 "requiring finalization");
+    const auto *details =
+        sym.detailsIf<Fortran::semantics::ObjectEntityDetails>();
+    if (details && details->init())
+      TODO(loc, "coarray: initialization");
+  }
 
   if (var.isModuleOrSubmoduleVariable()) {
     // A non-intrinsic module global is defined when lowering the module.
@@ -2634,11 +2639,12 @@ void Fortran::lower::mapSymbolAttributes(
     assert(!Fortran::semantics::IsAllocatable(sym) &&
            "must be a non-ALLOCATABLE coarray");
     if (Fortran::semantics::IsSaved(sym) &&
-        sym.owner().kind() != Fortran::semantics::Scope::Kind::MainProgram)
-      TODO(loc,
-           "coarray: non-ALLOCATABLE SAVE coarray outside the main program");
-    ;
-    Fortran::lower::genAllocateCoarray(converter, loc, sym, addr);
+        (sym.owner().kind() != Fortran::semantics::Scope::Kind::MainProgram ||
+         var.isModuleOrSubmoduleVariable()))
+      Fortran::lower::genAllocateNonAllocatableSaveCoarray(converter, loc, sym,
+                                                           addr);
+    else
+      Fortran::lower::genAllocateCoarray(converter, loc, sym, addr);
     ::genDeclareSymbol(converter, symMap, sym, addr, len, extents, lbounds,
                        replace);
     return;

diff  --git a/flang/lib/Lower/MultiImageFortran.cpp b/flang/lib/Lower/MultiImageFortran.cpp
index d5770dc197513..66ffca0b850dd 100644
--- a/flang/lib/Lower/MultiImageFortran.cpp
+++ b/flang/lib/Lower/MultiImageFortran.cpp
@@ -18,6 +18,8 @@
 #include "flang/Optimizer/Builder/MIFCommon.h"
 #include "flang/Optimizer/Builder/Todo.h"
 #include "flang/Parser/parse-tree.h"
+#include "flang/Semantics/expression.h"
+#include "mlir/IR/IRMapping.h"
 
 //===----------------------------------------------------------------------===//
 // Synchronization statements
@@ -449,6 +451,33 @@ mlir::Value Fortran::lower::genAllocateCoarray(
   return stat;
 }
 
+void Fortran::lower::genAllocateNonAllocatableSaveCoarray(
+    Fortran::lower::AbstractConverter &converter, mlir::Location loc,
+    const semantics::Symbol &sym, mlir::Value addr) {
+  fir::FirOpBuilder &builder = converter.getFirOpBuilder();
+  mlir::ModuleOp mod = builder.getModule();
+  mlir::IRMapping mapping;
+
+  auto func = mif::getOrCreateInitFunc(builder, mod, mifSaveCoarraysAllocName);
+  bool funcIsEmpty = func.empty();
+
+  mlir::Block &entry = func.getBody().front();
+  auto returnOp = entry.getTerminator();
+
+  mlir::OpBuilder::InsertionGuard guard(builder);
+  builder.setInsertionPoint(returnOp);
+
+  // If the function is empty, then we add the MIF initialization operation
+  // at the beginning.
+  if (funcIsEmpty)
+    mif::InitOp::create(builder, loc);
+
+  mlir::Operation &op = *addr.getDefiningOp();
+  mlir::Operation *localAddrOp = builder.clone(op, mapping);
+  Fortran::lower::genAllocateCoarray(converter, loc, sym,
+                                     localAddrOp->getResult(0));
+}
+
 //===----------------------------------------------------------------------===//
 // COARRAY expressions
 //===----------------------------------------------------------------------===//

diff  --git a/flang/lib/Optimizer/Builder/MIFCommon.cpp b/flang/lib/Optimizer/Builder/MIFCommon.cpp
index 8f08ce4573bbf..56225cda34fdb 100644
--- a/flang/lib/Optimizer/Builder/MIFCommon.cpp
+++ b/flang/lib/Optimizer/Builder/MIFCommon.cpp
@@ -7,6 +7,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "flang/Optimizer/Builder/MIFCommon.h"
+#include "flang/Lower/MultiImageFortran.h"
 #include "flang/Optimizer/Builder/FIRBuilder.h"
 #include "flang/Optimizer/Builder/HLFIRTools.h"
 #include "flang/Optimizer/Dialect/MIF/MIFOps.h"
@@ -80,3 +81,24 @@ mlir::Value mif::genImageIndex(fir::FirOpBuilder &builder, mlir::Location loc,
     (*subCastAndCleanup.second)();
   return imageIndex;
 }
+
+mlir::func::FuncOp mif::getOrCreateInitFunc(fir::FirOpBuilder &builder,
+                                            mlir::ModuleOp mod,
+                                            llvm::StringRef name) {
+  mlir::Location loc = mod.getLoc();
+  auto funcType = builder.getFunctionType({}, {});
+  auto func = builder.createFunction(loc, name, funcType);
+  if (!func.empty())
+    return func;
+
+  func.setPublic();
+  mlir::OpBuilder::InsertionGuard guard(builder);
+  builder.setInsertionPointToEnd(mod.getBody());
+
+  func.addEntryBlock();
+  builder.setInsertionPointToEnd(&func.getBody().front());
+  mif::InitOp::create(builder, loc);
+  mlir::func::ReturnOp::create(builder, loc);
+
+  return func;
+}

diff  --git a/flang/lib/Optimizer/Passes/Pipelines.cpp b/flang/lib/Optimizer/Passes/Pipelines.cpp
index 5fa70096e0e41..70ef9e9bd17bb 100644
--- a/flang/lib/Optimizer/Passes/Pipelines.cpp
+++ b/flang/lib/Optimizer/Passes/Pipelines.cpp
@@ -10,6 +10,7 @@
 /// common to flang and the test tools.
 
 #include "flang/Optimizer/Passes/Pipelines.h"
+#include "flang/Optimizer/Builder/MIFCommon.h"
 #include "flang/Optimizer/Dialect/FIROps.h"
 #include "flang/Optimizer/OpenACC/Passes.h"
 #include "mlir/Conversion/Passes.h"
@@ -460,6 +461,7 @@ void createDefaultFIRCodeGenPassPipeline(mlir::PassManager &pm,
   }
 
   fir::addFIRToLLVMPass(pm, config);
+  pm.addPass(fir::createEmitMIFGlobalCtors());
 
   if (config.EnableOpenMP && !config.EnableOpenMPSimd) {
     // Remove all non target-related operations from host functions still

diff  --git a/flang/lib/Optimizer/Transforms/CMakeLists.txt b/flang/lib/Optimizer/Transforms/CMakeLists.txt
index 0f062255f3ba4..8ff67d901b31d 100644
--- a/flang/lib/Optimizer/Transforms/CMakeLists.txt
+++ b/flang/lib/Optimizer/Transforms/CMakeLists.txt
@@ -28,6 +28,7 @@ add_flang_library(FIRTransforms
   ControlFlowConverter.cpp
   ConvertComplexPow.cpp
   DebugTypeGenerator.cpp
+  EmitMIFGlobalCtors.cpp
   ExternalNameConversion.cpp
   FIRToSCF.cpp
   FIRToMemRef.cpp

diff  --git a/flang/lib/Optimizer/Transforms/EmitMIFGlobalCtors.cpp b/flang/lib/Optimizer/Transforms/EmitMIFGlobalCtors.cpp
new file mode 100644
index 0000000000000..f5e2c35733f21
--- /dev/null
+++ b/flang/lib/Optimizer/Transforms/EmitMIFGlobalCtors.cpp
@@ -0,0 +1,100 @@
+//===-- EmitMIFGlobalCtors.cpp --------------------------------------------===//
+//
+// 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 "flang/Optimizer/Builder/MIFCommon.h"
+#include "flang/Optimizer/Builder/Runtime/Inquiry.h"
+#include "flang/Optimizer/Builder/Runtime/RTBuilder.h"
+#include "flang/Optimizer/Dialect/FIRDialect.h"
+#include "flang/Optimizer/Dialect/FIROps.h"
+#include "flang/Optimizer/Dialect/MIF/MIFOps.h"
+#include "mlir/Dialect/LLVMIR/LLVMDialect.h"
+#include "mlir/IR/Builders.h"
+#include "mlir/IR/BuiltinOps.h"
+#include "mlir/Pass/Pass.h"
+
+namespace fir {
+#define GEN_PASS_DEF_EMITMIFGLOBALCTORS
+#include "flang/Optimizer/Transforms/Passes.h.inc"
+} // namespace fir
+
+using namespace mlir;
+using namespace Fortran::runtime;
+
+namespace {
+
+class EmitMIFGlobalCtors
+    : public fir::impl::EmitMIFGlobalCtorsBase<EmitMIFGlobalCtors> {
+public:
+  void runOnOperation() override {
+    mlir::ModuleOp mod = getOperation();
+    mlir::MLIRContext *ctx = mod.getContext();
+    mlir::OpBuilder builder(ctx);
+    builder.setInsertionPointToEnd(mod.getBody());
+    mlir::Location loc = builder.getUnknownLoc();
+
+    llvm::SmallVector<mlir::Attribute> funcs, priorities, data;
+    mlir::Type i32Ty = mlir::IntegerType::get(ctx, 32);
+    mlir::Attribute zeroAttr = mlir::LLVM::ZeroAttr::get(builder.getContext());
+
+    // Setting priority 0 for the initialization of mif.
+    if (mod.lookupSymbol<mlir::LLVM::LLVMFuncOp>(mifSaveCoarraysAllocName)) {
+      funcs.push_back(
+          mlir::FlatSymbolRefAttr::get(ctx, mifSaveCoarraysAllocName));
+      priorities.push_back(mlir::IntegerAttr::get(i32Ty, 0));
+      data.push_back(zeroAttr);
+    }
+
+    if (funcs.empty())
+      return;
+
+    // We check whether a GlobalCtorsOp already exists to avoid having
+    // multiple instances.
+    mlir::LLVM::GlobalCtorsOp globalCtors;
+    mod.walk([&](mlir::LLVM::GlobalCtorsOp op) { globalCtors = op; });
+
+    if (globalCtors) {
+      llvm::SmallVector<mlir::Attribute> mergedFuncs(
+          globalCtors.getCtors().begin(), globalCtors.getCtors().end());
+      llvm::SmallVector<mlir::Attribute> mergedPriorities(
+          globalCtors.getPriorities().begin(),
+          globalCtors.getPriorities().end());
+      llvm::SmallVector<mlir::Attribute> mergedData(
+          globalCtors.getData().begin(), globalCtors.getData().end());
+
+      llvm::SmallDenseSet<llvm::StringRef> existingNames;
+      for (auto attr : globalCtors.getCtors())
+        existingNames.insert(
+            llvm::cast<mlir::FlatSymbolRefAttr>(attr).getValue());
+
+      for (auto [func, priority, d] : llvm::zip(funcs, priorities, data)) {
+        auto name = llvm::cast<mlir::FlatSymbolRefAttr>(func).getValue();
+        if (!existingNames.contains(name)) {
+          mergedFuncs.push_back(func);
+          mergedPriorities.push_back(priority);
+          mergedData.push_back(d);
+        }
+      }
+
+      // Deleting the existing GlobalCtorsOp and creating a new one that
+      // contains the merged attributes.
+      builder.setInsertionPoint(globalCtors);
+      mlir::LLVM::GlobalCtorsOp::create(builder, globalCtors.getLoc(),
+                                        builder.getArrayAttr(mergedFuncs),
+                                        builder.getArrayAttr(mergedPriorities),
+                                        builder.getArrayAttr(mergedData));
+      globalCtors.erase();
+    } else {
+      builder.setInsertionPointToEnd(mod.getBody());
+      mlir::LLVM::GlobalCtorsOp::create(
+          builder, loc, builder.getArrayAttr(funcs),
+          builder.getArrayAttr(priorities), builder.getArrayAttr(data));
+    }
+  }
+};
+
+} // namespace

diff  --git a/flang/test/Fir/basic-program.fir b/flang/test/Fir/basic-program.fir
index 471e5a89046eb..1fb7ed81f547c 100644
--- a/flang/test/Fir/basic-program.fir
+++ b/flang/test/Fir/basic-program.fir
@@ -184,6 +184,7 @@ func.func @_QQmain() {
 // PASSES-NEXT:  LowerNontemporalPass
 // PASSES-NEXT: FIRToLLVMLowering
 // PASSES-NEXT: ReconcileUnrealizedCasts
+// PASSES-NEXT: EmitMIFGlobalCtors
 // PASSES-NEXT:  HostOpFilteringPass
 // PASSES-NEXT: 'llvm.func' Pipeline
 // PASSES-NEXT:  StackToSharedPass

diff  --git a/flang/test/Lower/MIF/coarray_allocation4.f90 b/flang/test/Lower/MIF/coarray_allocation4.f90
index f0278ea2cd534..450fad07f9933 100644
--- a/flang/test/Lower/MIF/coarray_allocation4.f90
+++ b/flang/test/Lower/MIF/coarray_allocation4.f90
@@ -1,8 +1,76 @@
-! RUN: not %flang_fc1 -emit-hlfir -fcoarray %s -o - 2>&1 | FileCheck %s
+! RUN: %flang_fc1 -emit-hlfir -fcoarray %s -o - 2>&1 | FileCheck %s
+! RUN: %flang_fc1 -emit-llvm -fcoarray %s -o - 2>&1 | FileCheck %s --check-prefix=LLVM
 
-!CHECK: not yet implemented: coarray: non-ALLOCATABLE SAVE coarray outside the main program
+! LLVM: @llvm.global_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 0, ptr @__mif_save_coarrays_allocate, ptr null }]
 
 subroutine test_coarray_save()
     implicit none
     real, SAVE :: n[*]
+    real, SAVE :: m[*]
+    real, SAVE :: p[*]
 end subroutine test_coarray_save
+
+program main
+  call test_coarray_save()
+end program
+
+! CHECK-LABEL: func.func @_QPtest_coarray_save()
+! CHECK:   %0 = fir.dummy_scope : !fir.dscope
+! CHECK:   %1 = fir.address_of(@_QFtest_coarray_saveEm) : !fir.ref<f32>
+! CHECK:   %2:2 = hlfir.declare %1 {uniq_name = "_QFtest_coarray_saveEm"} : (!fir.ref<f32>) -> (!fir.ref<f32>, !fir.ref<f32>)
+! CHECK:   %3 = fir.address_of(@_QFtest_coarray_saveEn) : !fir.ref<f32>
+! CHECK:   %4:2 = hlfir.declare %3 {uniq_name = "_QFtest_coarray_saveEn"} : (!fir.ref<f32>) -> (!fir.ref<f32>, !fir.ref<f32>)
+! CHECK:   %5 = fir.address_of(@_QFtest_coarray_saveEp) : !fir.ref<f32>
+! CHECK:   %6:2 = hlfir.declare %5 {uniq_name = "_QFtest_coarray_saveEp"} : (!fir.ref<f32>) -> (!fir.ref<f32>, !fir.ref<f32>)
+! CHECK:   return
+
+! CHECK-LABEL: func.func @_QQmain() attributes {fir.bindc_name = "MAIN"}
+! CHECK:   %0 = fir.dummy_scope : !fir.dscope
+! CHECK:   fir.call @_QPtest_coarray_save() fastmath<contract> : () -> ()
+! CHECK:   return
+
+! CHECK: fir.global internal @_QFtest_coarray_saveEm : f32
+
+! CHECK-LABEL: func.func @__mif_save_coarrays_allocate()
+! CHECK:   %[[VAL_0:.*]] = fir.alloca !fir.array<0xi64>
+! CHECK:   %[[VAL_1:.*]] = fir.alloca !fir.array<1xi64>
+! CHECK:   %[[VAL_2:.*]] = fir.alloca !fir.array<0xi64>
+! CHECK:   %[[VAL_3:.*]] = fir.alloca !fir.array<1xi64>
+! CHECK:   %[[VAL_4:.*]] = fir.alloca !fir.array<0xi64>
+! CHECK:   %[[VAL_5:.*]] = fir.alloca !fir.array<1xi64>
+! CHECK:   %[[INIT_STAT:.*]] = mif.init -> i32
+! CHECK:   %[[VAL_6:.*]] = fir.address_of(@_QFtest_coarray_saveEm) : !fir.ref<f32>
+! CHECK:   %[[C1_I64:.*]] = arith.constant 1 : i64
+! CHECK:   %[[C1_I64_0:.*]] = arith.constant 1 : i64
+! CHECK:   %[[C0:.*]] = arith.constant 0 : index
+! CHECK:   %[[VAL_7:.*]] = fir.coordinate_of %[[VAL_5]], %[[C0]] : (!fir.ref<!fir.array<1xi64>>, index) -> !fir.ref<i64>
+! CHECK:   fir.store %[[C1_I64_0]] to %[[VAL_7]] : !fir.ref<i64>
+! CHECK:   %[[VAL_8:.*]] = fir.embox %[[VAL_5]] : (!fir.ref<!fir.array<1xi64>>) -> !fir.box<!fir.array<1xi64>>
+! CHECK:   %[[C1_I64_1:.*]] = arith.constant 1 : i64
+! CHECK:   %[[VAL_9:.*]] = fir.embox %[[VAL_4]] : (!fir.ref<!fir.array<0xi64>>) -> !fir.box<!fir.array<0xi64>>
+! CHECK:   mif.alloc_coarray %[[VAL_6]] lcobounds %[[VAL_8]] ucobounds %[[VAL_9]] {uniq_name = "_QFtest_coarray_saveEm"} : (!fir.ref<f32>, !fir.box<!fir.array<1xi64>>, !fir.box<!fir.array<0xi64>>) -> ()
+! CHECK:   %[[VAL_10:.*]] = fir.address_of(@_QFtest_coarray_saveEn) : !fir.ref<f32>
+! CHECK:   %[[C1_I64_2:.*]] = arith.constant 1 : i64
+! CHECK:   %[[C1_I64_3:.*]] = arith.constant 1 : i64
+! CHECK:   %[[C0_4:.*]] = arith.constant 0 : index
+! CHECK:   %[[VAL_11:.*]] = fir.coordinate_of %[[VAL_3]], %[[C0_4]] : (!fir.ref<!fir.array<1xi64>>, index) -> !fir.ref<i64>
+! CHECK:   fir.store %[[C1_I64_3]] to %[[VAL_11]] : !fir.ref<i64>
+! CHECK:   %[[VAL_12:.*]] = fir.embox %[[VAL_3]] : (!fir.ref<!fir.array<1xi64>>) -> !fir.box<!fir.array<1xi64>>
+! CHECK:   %[[C1_I64_5:.*]] = arith.constant 1 : i64
+! CHECK:   %[[VAL_13:.*]] = fir.embox %[[VAL_2]] : (!fir.ref<!fir.array<0xi64>>) -> !fir.box<!fir.array<0xi64>>
+! CHECK:   mif.alloc_coarray %[[VAL_10]] lcobounds %[[VAL_12]] ucobounds %[[VAL_13]] {uniq_name = "_QFtest_coarray_saveEn"} : (!fir.ref<f32>, !fir.box<!fir.array<1xi64>>, !fir.box<!fir.array<0xi64>>) -> ()
+! CHECK:   %[[VAL_14:.*]] = fir.address_of(@_QFtest_coarray_saveEp) : !fir.ref<f32>
+! CHECK:   %[[C1_I64_6:.*]] = arith.constant 1 : i64
+! CHECK:   %[[C1_I64_7:.*]] = arith.constant 1 : i64
+! CHECK:   %[[C0_8:.*]] = arith.constant 0 : index
+! CHECK:   %[[VAL_15:.*]] = fir.coordinate_of %[[VAL_1]], %[[C0_8]] : (!fir.ref<!fir.array<1xi64>>, index) -> !fir.ref<i64>
+! CHECK:   fir.store %[[C1_I64_7]] to %[[VAL_15]] : !fir.ref<i64>
+! CHECK:   %[[VAL_16:.*]] = fir.embox %[[VAL_1]] : (!fir.ref<!fir.array<1xi64>>) -> !fir.box<!fir.array<1xi64>>
+! CHECK:   %[[VAL_C1_I64_9:.*]] = arith.constant 1 : i64
+! CHECK:   %[[VAL_17:.*]] = fir.embox %[[VAL_0]] : (!fir.ref<!fir.array<0xi64>>) -> !fir.box<!fir.array<0xi64>>
+! CHECK:   mif.alloc_coarray %[[VAL_14:.*]] lcobounds %[[VAL_16]] ucobounds %[[VAL_17]] {uniq_name = "_QFtest_coarray_saveEp"} : (!fir.ref<f32>, !fir.box<!fir.array<1xi64>>, !fir.box<!fir.array<0xi64>>) -> ()
+! CHECK:   return
+
+! CHECK:  fir.global internal @_QFtest_coarray_saveEn : f32
+! CHECK:  fir.global internal @_QFtest_coarray_saveEp : f32
+

diff  --git a/flang/test/Lower/MIF/coarray_allocation5.f90 b/flang/test/Lower/MIF/coarray_allocation5.f90
index 42058363bf9fb..c1a7958b67454 100644
--- a/flang/test/Lower/MIF/coarray_allocation5.f90
+++ b/flang/test/Lower/MIF/coarray_allocation5.f90
@@ -1,8 +1,29 @@
-! RUN: not %flang_fc1 -emit-hlfir -fcoarray %s -o - 2>&1 | FileCheck %s
-
-!CHECK: not yet implemented: coarray: non-ALLOCATABLE SAVE coarray outside the main program
+! RUN: %flang_fc1 -emit-hlfir -fcoarray %s -o - | FileCheck %s
+! RUN: %flang_fc1 -emit-llvm -fcoarray %s -o - 2>&1 | FileCheck %s --check-prefix=LLVM
 
 module m_coarray_test
     implicit none
     real :: module_coarray[*]
 end module m_coarray_test
+
+program test
+  use m_coarray_test
+end program
+
+! LLVM: @llvm.global_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 0, ptr @__mif_save_coarrays_allocate, ptr null }]
+
+! CHECK-LABEL: func.func @__mif_save_coarrays_allocate()
+! CHECK:  %[[VAL_0:.*]] = fir.alloca !fir.array<0xi64>
+! CHECK:  %[[VAL_1:.*]] = fir.alloca !fir.array<1xi64>
+! CHECK:  %[[INIT_STAT:.*]] = mif.init -> i32
+! CHECK:  %[[VAL_2:.*]] = fir.address_of(@_QMm_coarray_testEmodule_coarray) : !fir.ref<f32>
+! CHECK:  %c1_i64 = arith.constant 1 : i64
+! CHECK:  %c1_i64_0 = arith.constant 1 : i64
+! CHECK:  %c0 = arith.constant 0 : index
+! CHECK:  %[[VAL_3:.*]] = fir.coordinate_of %[[VAL_1]], %c0 : (!fir.ref<!fir.array<1xi64>>, index) -> !fir.ref<i64>
+! CHECK:  fir.store %c1_i64_0 to %[[VAL_3]] : !fir.ref<i64>
+! CHECK:  %[[VAL_4:.*]] = fir.embox %[[VAL_1]] : (!fir.ref<!fir.array<1xi64>>) -> !fir.box<!fir.array<1xi64>>
+! CHECK:  %c1_i64_1 = arith.constant 1 : i64
+! CHECK:  %[[VAL_5:.*]] = fir.embox %[[VAL_0]] : (!fir.ref<!fir.array<0xi64>>) -> !fir.box<!fir.array<0xi64>>
+! CHECK:  mif.alloc_coarray %[[VAL_2]] lcobounds %[[VAL_4]] ucobounds %[[VAL_5]] {uniq_name = "_QMm_coarray_testEmodule_coarray"} : (!fir.ref<f32>, !fir.box<!fir.array<1xi64>>, !fir.box<!fir.array<0xi64>>) -> ()
+! CHECK:  return


        


More information about the flang-commits mailing list