[flang-commits] [flang] [flang] Preserve capture metadata for host-associated globals (PR #233433)

Sergey Shcherbinin via flang-commits flang-commits at lists.llvm.org
Mon Oct 19 06:51:36 PDT 2026


https://github.com/SergeyShch01 created https://github.com/llvm/llvm-project/pull/233433

Host-associated globals accessed directly inside internal procedures are missing `internal_assoc`. For SAVE variables, FIR alias analysis can then treat a sibling internal call as `NoModRef`, allowing FIR LICM to hoist loads incorrectly.

Use the host procedure's existing global-capture set when lowering canonical host globals. Exact symbol identity keeps OpenMP private copies separate from their originals, and the existing alias-analysis handling of `internal_assoc` protects the captured storage.

For example:

```fortran
program p
  integer, save :: x = 0
  print *, f()
contains
  integer function f()
    integer :: i
    f = 0
    do i = 1, 3
      call bump()
      f = f + x
    end do
  end function
  subroutine bump()
    x = x + 1
  end subroutine
end program
```

The expected result is **6**. Runtime checks on AArch64, comparing unpatched upstream `b0e32db0ae5a` with the same revision plus this fix, produced:

| Build | `-O0` | `-O1` | `-O2` | `-O3` |
| --- | ---: | ---: | ---: | ---: |
| Unpatched upstream | **6** | 0 | 0 | 0 |
| With this fix | **6** | **6** | **6** | **6** |

Disabling FIR LICM on unpatched upstream with `-O2 -mmlir -disable-fir-licm` also restores **6**. No `-fsave-main-program` flag is needed for this reproducer.

Regression coverage includes explicit and initialization-implied SAVE, `-fsave-main-program`, `-fno-automatic`, and private/firstprivate/reduction copies.


>From c49494eb94b0188c9f610796f26dadfad9832d78 Mon Sep 17 00:00:00 2001
From: Sergey Shcherbinin <sscherbinin at nvidia.com>
Date: Mon, 19 Oct 2026 15:19:14 +0400
Subject: [PATCH] [flang] Preserve capture metadata for host-associated globals

Internal procedures address host globals directly. Without internal_assoc on
these declarations, alias analysis can miss writes through sibling internal
calls and LICM can hoist dependent loads out of loops.

Use the host global-capture set to identify canonical host storage when
lowering internal procedures. Exact symbol identity keeps private copies
separate from their host originals.

Add lowering and LICM regressions for SAVE, initialized globals,
-fsave-main-program, -fno-automatic and private/firstprivate/reduction copies.
Update existing host-association expectations for the preserved metadata.
---
 flang/include/flang/Lower/HostAssociations.h  |  5 +
 .../flang/Optimizer/Dialect/FIRAttr.td        |  2 +-
 flang/lib/Lower/ConvertVariable.cpp           | 14 ++-
 .../Lower/MIF/coarray_alloc_many_declare.f90  |  2 +-
 .../host-associated-globals-private.f90       | 39 ++++++++
 .../threadprivate-host-association-2.f90      |  6 +-
 .../threadprivate-host-association-3.f90      |  6 +-
 .../OpenMP/threadprivate-host-association.f90 |  6 +-
 .../Lower/equivalence-with-host-assoc.f90     | 20 ++--
 .../Lower/host-associated-globals-licm.f90    | 96 +++++++++++++++++++
 flang/test/Lower/host-associated-globals.f90  | 10 +-
 flang/test/Lower/volatile4.f90                |  6 +-
 12 files changed, 182 insertions(+), 30 deletions(-)
 create mode 100644 flang/test/Lower/OpenMP/host-associated-globals-private.f90
 create mode 100644 flang/test/Lower/host-associated-globals-licm.f90

diff --git a/flang/include/flang/Lower/HostAssociations.h b/flang/include/flang/Lower/HostAssociations.h
index 599dcb18d7e45..ee9136d80ea94 100644
--- a/flang/include/flang/Lower/HostAssociations.h
+++ b/flang/include/flang/Lower/HostAssociations.h
@@ -56,6 +56,11 @@ class HostAssociations {
     return tupleSymbols.contains(&symbol) || globalSymbols.contains(&symbol);
   }
 
+  /// Is the canonical symbol captured as a global instead of a tuple entry?
+  bool isAssociatedGlobal(const Fortran::semantics::Symbol &symbol) const {
+    return globalSymbols.contains(&symbol);
+  }
+
 private:
   /// Canonical vector of host associated local symbols.
   llvm::SetVector<const Fortran::semantics::Symbol *> tupleSymbols;
diff --git a/flang/include/flang/Optimizer/Dialect/FIRAttr.td b/flang/include/flang/Optimizer/Dialect/FIRAttr.td
index 581c831c8985e..c8ee7f88291c5 100644
--- a/flang/include/flang/Optimizer/Dialect/FIRAttr.td
+++ b/flang/include/flang/Optimizer/Dialect/FIRAttr.td
@@ -82,7 +82,7 @@ def FIRvalue        : I32BitEnumAttrCaseBit<"value", 11>;
 def FIRvolatile     : I32BitEnumAttrCaseBit<"fortran_volatile", 12, "volatile">;
 // Used inside internal procedure to flag variables host associated from parent procedure.
 def FIRHostAssoc    : I32BitEnumAttrCaseBit<"host_assoc", 13>;
-// Used inside parent procedure to flag variables host associated in internal procedure.
+// Marks storage accessible to internal procedures through host association.
 def FIRInternalAssoc    : I32BitEnumAttrCaseBit<"internal_assoc", 14>;
 // Used by alias analysis
 def FIRcray_pointer : I32BitEnumAttrCaseBit<"cray_pointer", 15>;
diff --git a/flang/lib/Lower/ConvertVariable.cpp b/flang/lib/Lower/ConvertVariable.cpp
index 59f46a31256fe..cc5bdfbcda0d9 100644
--- a/flang/lib/Lower/ConvertVariable.cpp
+++ b/flang/lib/Lower/ConvertVariable.cpp
@@ -2550,12 +2550,24 @@ fir::FortranVariableFlagsAttr Fortran::lower::translateSymbolAttributes(
   return fir::FortranVariableFlagsAttr::get(mlirContext, flags);
 }
 
+/// Whether storage may be accessed indirectly through internal procedure calls.
 static bool
 isCapturedInInternalProcedure(Fortran::lower::AbstractConverter &converter,
                               const Fortran::semantics::Symbol &sym) {
   const Fortran::lower::pft::FunctionLikeUnit *funit =
       converter.getCurrentFunctionUnit();
-  if (!funit || funit->getHostAssoc().empty())
+  if (!funit)
+    return false;
+  if (const auto *host =
+          funit->parent.getIf<Fortran::lower::pft::FunctionLikeUnit>()) {
+    // Only canonical host globals share storage with sibling procedures.
+    // Private copies can resolve to the same ultimate symbol but have separate
+    // storage and are absent from the canonical global capture set.
+    if (&sym.owner() == &host->getScope() &&
+        host->getHostAssoc().isAssociatedGlobal(sym))
+      return true;
+  }
+  if (funit->getHostAssoc().empty())
     return false;
   if (funit->getHostAssoc().isAssociated(sym))
     return true;
diff --git a/flang/test/Lower/MIF/coarray_alloc_many_declare.f90 b/flang/test/Lower/MIF/coarray_alloc_many_declare.f90
index b7d004321a7b5..c4ead3c66c694 100644
--- a/flang/test/Lower/MIF/coarray_alloc_many_declare.f90
+++ b/flang/test/Lower/MIF/coarray_alloc_many_declare.f90
@@ -29,7 +29,7 @@ end program p
 !CHECK-LABEL: func.func private @_QFPinner() attributes {fir.host_symbol = @_QQmain, llvm.linkage = #llvm.linkage<internal>}
 !CHECK:       %[[VAL_0:.*]] = fir.dummy_scope : !fir.dscope
 !CHECK-NEXT:  %[[VAL_1:.*]] = fir.address_of(@_QFEa) : !fir.ref<!fir.box<!fir.heap<i32>, corank:1>>
-!CHECK-NEXT:  %[[VAL_2:.*]]:2 = hlfir.declare %[[VAL_1]] uniq_name("_QFEa") fortran_attrs<allocatable> : (!fir.ref<!fir.box<!fir.heap<i32>, corank:1>>) -> (!fir.ref<!fir.box<!fir.heap<i32>, corank:1>>, !fir.ref<!fir.box<!fir.heap<i32>, corank:1>>)
+!CHECK-NEXT:  %[[VAL_2:.*]]:2 = hlfir.declare %[[VAL_1]] uniq_name("_QFEa") fortran_attrs<allocatable, internal_assoc> : (!fir.ref<!fir.box<!fir.heap<i32>, corank:1>>) -> (!fir.ref<!fir.box<!fir.heap<i32>, corank:1>>, !fir.ref<!fir.box<!fir.heap<i32>, corank:1>>)
 !CHECK-NEXT:  %c1_i32 = arith.constant 1 : i32
 !CHECK-NEXT:  hlfir.assign %c1_i32 to %[[VAL_2:.*]]#0 realloc : i32, !fir.ref<!fir.box<!fir.heap<i32>, corank:1>>
 
diff --git a/flang/test/Lower/OpenMP/host-associated-globals-private.f90 b/flang/test/Lower/OpenMP/host-associated-globals-private.f90
new file mode 100644
index 0000000000000..0b6ff226a38d4
--- /dev/null
+++ b/flang/test/Lower/OpenMP/host-associated-globals-private.f90
@@ -0,0 +1,39 @@
+! REQUIRES: module-independent
+! RUN: %flang_fc1 -fopenmp -emit-hlfir %s -o - | FileCheck %s
+! RUN: bbc -fopenmp -emit-hlfir %s -o - | FileCheck %s
+
+! Canonical SAVE globals remain accessible through sibling calls. Each OpenMP
+! copy has separate storage and must not inherit internal_assoc from its source.
+! CHECK-LABEL: func.func private @_QFhPworker()
+! CHECK-DAG: hlfir.declare {{.*}}uniq_name("_QFhEx") fortran_attrs<internal_assoc>
+! CHECK-DAG: hlfir.declare {{.*}}uniq_name("_QFhEy") fortran_attrs<internal_assoc>
+! CHECK-DAG: hlfir.declare {{.*}}uniq_name("_QFhEz") fortran_attrs<internal_assoc>
+! CHECK: omp.parallel
+! CHECK-DAG: hlfir.declare %arg0 uniq_name("_QFhEx") :
+! CHECK-DAG: hlfir.declare %arg1 uniq_name("_QFhEy") :
+! CHECK-DAG: hlfir.declare %arg2 uniq_name("_QFhEz") :
+! CHECK-LABEL: func.func private @_QFhPbump()
+! CHECK-DAG: hlfir.declare {{.*}}uniq_name("_QFhEx") fortran_attrs<internal_assoc>
+! CHECK-DAG: hlfir.declare {{.*}}uniq_name("_QFhEy") fortran_attrs<internal_assoc>
+! CHECK-DAG: hlfir.declare {{.*}}uniq_name("_QFhEz") fortran_attrs<internal_assoc>
+subroutine h
+  integer, save :: x,y,z
+  x=7
+  y=8
+  z=9
+  call worker()
+contains
+  subroutine worker()
+!$omp parallel num_threads(1) firstprivate(x) private(y) reduction(+:z)
+    call bump()
+    y=x
+    z=z+y
+    print *,x,y,z
+!$omp end parallel
+  end subroutine
+  subroutine bump()
+    x=x+1
+    y=y+1
+    z=z+1
+  end subroutine
+end subroutine
diff --git a/flang/test/Lower/OpenMP/threadprivate-host-association-2.f90 b/flang/test/Lower/OpenMP/threadprivate-host-association-2.f90
index c632e12483af6..917c38b791266 100644
--- a/flang/test/Lower/OpenMP/threadprivate-host-association-2.f90
+++ b/flang/test/Lower/OpenMP/threadprivate-host-association-2.f90
@@ -14,13 +14,13 @@
 !CHECK: }
 !CHECK: func.func private @_QFPsub() attributes {fir.host_symbol = {{.*}}, llvm.linkage = #llvm.linkage<internal>} {
 !CHECK:   %[[A:.*]] = fir.alloca i32 <{bindc_name = "a", uniq_name = "_QFEa"}>
-!CHECK:   %[[A_DECL:.*]]:2 = hlfir.declare %[[A]] uniq_name("_QFEa") : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+!CHECK:   %[[A_DECL:.*]]:2 = hlfir.declare %[[A]] uniq_name("_QFEa") fortran_attrs<internal_assoc> : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
 !CHECK:   %[[A_ADDR:.*]] = fir.address_of(@_QFEa) : !fir.ref<i32>
 !CHECK:   %[[TP_A:.*]] = omp.threadprivate %[[A_ADDR]] : !fir.ref<i32> -> !fir.ref<i32>
-!CHECK:   %[[TP_A_DECL:.*]]:2 = hlfir.declare %[[TP_A]] uniq_name("_QFEa") : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+!CHECK:   %[[TP_A_DECL:.*]]:2 = hlfir.declare %[[TP_A]] uniq_name("_QFEa") fortran_attrs<internal_assoc> : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
 !CHECK:   omp.parallel {
 !CHECK:     %[[PAR_TP_A:.*]] = omp.threadprivate %[[A_ADDR]] : !fir.ref<i32> -> !fir.ref<i32>
-!CHECK:     %[[PAR_TP_A_DECL:.*]]:2 = hlfir.declare %[[PAR_TP_A]] uniq_name("_QFEa") : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+!CHECK:     %[[PAR_TP_A_DECL:.*]]:2 = hlfir.declare %[[PAR_TP_A]] uniq_name("_QFEa") fortran_attrs<internal_assoc> : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
 !CHECK:     %{{.*}} = fir.load %[[PAR_TP_A_DECL]]#0 : !fir.ref<i32>
 !CHECK:     omp.terminator
 !CHECK:   }
diff --git a/flang/test/Lower/OpenMP/threadprivate-host-association-3.f90 b/flang/test/Lower/OpenMP/threadprivate-host-association-3.f90
index 3219b61f436ee..0e411d80167f1 100644
--- a/flang/test/Lower/OpenMP/threadprivate-host-association-3.f90
+++ b/flang/test/Lower/OpenMP/threadprivate-host-association-3.f90
@@ -14,13 +14,13 @@
 !CHECK: }
 !CHECK: func.func private @_QFPsub() attributes {fir.host_symbol = {{.*}}, llvm.linkage = #llvm.linkage<internal>} {
 !CHECK:   %[[A:.*]] = fir.alloca i32 <{bindc_name = "a", uniq_name = "_QFEa"}>
-!CHECK:   %[[A_DECL:.*]]:2 = hlfir.declare %[[A]] uniq_name("_QFEa") : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+!CHECK:   %[[A_DECL:.*]]:2 = hlfir.declare %[[A]] uniq_name("_QFEa") fortran_attrs<internal_assoc> : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
 !CHECK:   %[[A_ADDR:.*]] = fir.address_of(@_QFEa) : !fir.ref<i32>
 !CHECK:   %[[TP_A:.*]] = omp.threadprivate %[[A_ADDR]] : !fir.ref<i32> -> !fir.ref<i32>
-!CHECK:   %[[TP_A_DECL:.*]]:2 = hlfir.declare %[[TP_A]] uniq_name("_QFEa") : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+!CHECK:   %[[TP_A_DECL:.*]]:2 = hlfir.declare %[[TP_A]] uniq_name("_QFEa") fortran_attrs<internal_assoc> : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
 !CHECK:   omp.parallel {
 !CHECK:     %[[PAR_TP_A:.*]] = omp.threadprivate %[[A_ADDR]] : !fir.ref<i32> -> !fir.ref<i32>
-!CHECK:     %[[PAR_TP_A_DECL:.*]]:2 = hlfir.declare %[[PAR_TP_A]] uniq_name("_QFEa") : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+!CHECK:     %[[PAR_TP_A_DECL:.*]]:2 = hlfir.declare %[[PAR_TP_A]] uniq_name("_QFEa") fortran_attrs<internal_assoc> : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
 !CHECK:     %{{.*}} = fir.load %[[PAR_TP_A_DECL]]#0 : !fir.ref<i32>
 !CHECK:     omp.terminator
 !CHECK:   }
diff --git a/flang/test/Lower/OpenMP/threadprivate-host-association.f90 b/flang/test/Lower/OpenMP/threadprivate-host-association.f90
index f57ef2c422163..4e17486d096a4 100644
--- a/flang/test/Lower/OpenMP/threadprivate-host-association.f90
+++ b/flang/test/Lower/OpenMP/threadprivate-host-association.f90
@@ -13,12 +13,12 @@
 !CHECK: }
 !CHECK: func.func private @_QFPsub() attributes {fir.host_symbol = {{.*}}, llvm.linkage = #llvm.linkage<internal>} {
 !CHECK:   %[[A:.*]] = fir.address_of(@_QFEa) : !fir.ref<i32>
-!CHECK:   %[[A_DECL:.*]]:2 = hlfir.declare %[[A]] uniq_name("_QFEa") : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+!CHECK:   %[[A_DECL:.*]]:2 = hlfir.declare %[[A]] uniq_name("_QFEa") fortran_attrs<internal_assoc> : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
 !CHECK:   %[[TP_A:.*]] = omp.threadprivate %[[A_DECL]]#0 : !fir.ref<i32> -> !fir.ref<i32>
-!CHECK:   %[[TP_A_DECL:.*]]:2 = hlfir.declare %[[TP_A]] uniq_name("_QFEa") : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+!CHECK:   %[[TP_A_DECL:.*]]:2 = hlfir.declare %[[TP_A]] uniq_name("_QFEa") fortran_attrs<internal_assoc> : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
 !CHECK:   omp.parallel {
 !CHECK:     %[[PAR_TP_A:.*]] = omp.threadprivate %[[A_DECL]]#0 : !fir.ref<i32> -> !fir.ref<i32>
-!CHECK:     %[[PAR_TP_A_DECL:.*]]:2 = hlfir.declare %[[PAR_TP_A]] uniq_name("_QFEa") : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+!CHECK:     %[[PAR_TP_A_DECL:.*]]:2 = hlfir.declare %[[PAR_TP_A]] uniq_name("_QFEa") fortran_attrs<internal_assoc> : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
 !CHECK:     %{{.*}} = fir.load %[[PAR_TP_A_DECL]]#0 : !fir.ref<i32>
 !CHECK:     omp.terminator
 !CHECK:   }
diff --git a/flang/test/Lower/equivalence-with-host-assoc.f90 b/flang/test/Lower/equivalence-with-host-assoc.f90
index 41cc27589c211..192d31a9acc6c 100644
--- a/flang/test/Lower/equivalence-with-host-assoc.f90
+++ b/flang/test/Lower/equivalence-with-host-assoc.f90
@@ -15,11 +15,11 @@ end subroutine test1
 ! HLFIR:           %[[VAL_2:.*]] = arith.constant 0 : index
 ! HLFIR:           %[[VAL_3:.*]] = fir.coordinate_of %[[VAL_1]], %[[VAL_2]] : (!fir.ref<!fir.array<4xi8>>, index) -> !fir.ref<i8>
 ! HLFIR:           %[[VAL_4:.*]] = fir.convert %[[VAL_3]] : (!fir.ref<i8>) -> !fir.ptr<i32>
-! HLFIR:           %[[VAL_5:.*]]:2 = hlfir.declare %[[VAL_4]] storage(%[[VAL_1]][0]) uniq_name("_QFtest1Ei1") : (!fir.ptr<i32>, !fir.ref<!fir.array<4xi8>>) -> (!fir.ptr<i32>, !fir.ptr<i32>)
+! HLFIR:           %[[VAL_5:.*]]:2 = hlfir.declare %[[VAL_4]] storage(%[[VAL_1]][0]) uniq_name("_QFtest1Ei1") fortran_attrs<internal_assoc> : (!fir.ptr<i32>, !fir.ref<!fir.array<4xi8>>) -> (!fir.ptr<i32>, !fir.ptr<i32>)
 ! HLFIR:           %[[VAL_6:.*]] = arith.constant 0 : index
 ! HLFIR:           %[[VAL_7:.*]] = fir.coordinate_of %[[VAL_1]], %[[VAL_6]] : (!fir.ref<!fir.array<4xi8>>, index) -> !fir.ref<i8>
 ! HLFIR:           %[[VAL_8:.*]] = fir.convert %[[VAL_7]] : (!fir.ref<i8>) -> !fir.ptr<i32>
-! HLFIR:           %[[VAL_9:.*]]:2 = hlfir.declare %[[VAL_8]] storage(%[[VAL_1]][0]) uniq_name("_QFtest1Ej1") : (!fir.ptr<i32>, !fir.ref<!fir.array<4xi8>>) -> (!fir.ptr<i32>, !fir.ptr<i32>)
+! HLFIR:           %[[VAL_9:.*]]:2 = hlfir.declare %[[VAL_8]] storage(%[[VAL_1]][0]) uniq_name("_QFtest1Ej1") fortran_attrs<internal_assoc> : (!fir.ptr<i32>, !fir.ref<!fir.array<4xi8>>) -> (!fir.ptr<i32>, !fir.ptr<i32>)
 ! HLFIR:           %[[VAL_10:.*]] = fir.load %[[VAL_9]]#0 : !fir.ptr<i32>
 ! HLFIR:           hlfir.assign %[[VAL_10]] to %[[VAL_5]]#0 : i32, !fir.ptr<i32>
 ! HLFIR:           return
@@ -45,11 +45,11 @@ end module test2
 ! HLFIR:           %[[VAL_2:.*]] = arith.constant 0 : index
 ! HLFIR:           %[[VAL_3:.*]] = fir.coordinate_of %[[VAL_1]], %[[VAL_2]] : (!fir.ref<!fir.array<4xi8>>, index) -> !fir.ref<i8>
 ! HLFIR:           %[[VAL_4:.*]] = fir.convert %[[VAL_3]] : (!fir.ref<i8>) -> !fir.ptr<f32>
-! HLFIR:           %[[VAL_5:.*]]:2 = hlfir.declare %[[VAL_4]] storage(%[[VAL_1]][0]) uniq_name("_QMtest2FhostEf1") : (!fir.ptr<f32>, !fir.ref<!fir.array<4xi8>>) -> (!fir.ptr<f32>, !fir.ptr<f32>)
+! HLFIR:           %[[VAL_5:.*]]:2 = hlfir.declare %[[VAL_4]] storage(%[[VAL_1]][0]) uniq_name("_QMtest2FhostEf1") fortran_attrs<internal_assoc> : (!fir.ptr<f32>, !fir.ref<!fir.array<4xi8>>) -> (!fir.ptr<f32>, !fir.ptr<f32>)
 ! HLFIR:           %[[VAL_6:.*]] = arith.constant 0 : index
 ! HLFIR:           %[[VAL_7:.*]] = fir.coordinate_of %[[VAL_1]], %[[VAL_6]] : (!fir.ref<!fir.array<4xi8>>, index) -> !fir.ref<i8>
 ! HLFIR:           %[[VAL_8:.*]] = fir.convert %[[VAL_7]] : (!fir.ref<i8>) -> !fir.ptr<f32>
-! HLFIR:           %[[VAL_9:.*]]:2 = hlfir.declare %[[VAL_8]] storage(%[[VAL_1]][0]) uniq_name("_QMtest2FhostEf2") : (!fir.ptr<f32>, !fir.ref<!fir.array<4xi8>>) -> (!fir.ptr<f32>, !fir.ptr<f32>)
+! HLFIR:           %[[VAL_9:.*]]:2 = hlfir.declare %[[VAL_8]] storage(%[[VAL_1]][0]) uniq_name("_QMtest2FhostEf2") fortran_attrs<internal_assoc> : (!fir.ptr<f32>, !fir.ref<!fir.array<4xi8>>) -> (!fir.ptr<f32>, !fir.ptr<f32>)
 ! HLFIR:           %[[VAL_19:.*]] = fir.load %[[VAL_9]]#0 : !fir.ptr<f32>
 ! HLFIR:           hlfir.assign %[[VAL_19]] to %[[VAL_5]]#0 : f32, !fir.ptr<f32>
 ! HLFIR:           return
@@ -71,17 +71,17 @@ end subroutine test3
 ! HLFIR:           %[[VAL_2:.*]] = arith.constant 0 : index
 ! HLFIR:           %[[VAL_3:.*]] = fir.coordinate_of %[[VAL_1]], %[[VAL_2]] : (!fir.ref<!fir.array<4xi8>>, index) -> !fir.ref<i8>
 ! HLFIR:           %[[VAL_4:.*]] = fir.convert %[[VAL_3]] : (!fir.ref<i8>) -> !fir.ptr<i32>
-! HLFIR:           %[[VAL_5:.*]]:2 = hlfir.declare %[[VAL_4]] storage(%[[VAL_1]][0]) uniq_name("_QFtest3Ei1") : (!fir.ptr<i32>, !fir.ref<!fir.array<4xi8>>) -> (!fir.ptr<i32>, !fir.ptr<i32>)
+! HLFIR:           %[[VAL_5:.*]]:2 = hlfir.declare %[[VAL_4]] storage(%[[VAL_1]][0]) uniq_name("_QFtest3Ei1") fortran_attrs<internal_assoc> : (!fir.ptr<i32>, !fir.ref<!fir.array<4xi8>>) -> (!fir.ptr<i32>, !fir.ptr<i32>)
 ! HLFIR:           %[[VAL_6:.*]] = fir.convert %[[VAL_0]] : (!fir.ref<tuple<i32>>) -> !fir.ref<!fir.array<4xi8>>
 ! HLFIR:           %[[VAL_7:.*]] = arith.constant 0 : index
 ! HLFIR:           %[[VAL_8:.*]] = fir.coordinate_of %[[VAL_6]], %[[VAL_7]] : (!fir.ref<!fir.array<4xi8>>, index) -> !fir.ref<i8>
 ! HLFIR:           %[[VAL_9:.*]] = fir.convert %[[VAL_8]] : (!fir.ref<i8>) -> !fir.ptr<i32>
-! HLFIR:           %[[VAL_10:.*]]:2 = hlfir.declare %[[VAL_9]] storage(%[[VAL_6]][0]) uniq_name("_QFtest3Ej1") : (!fir.ptr<i32>, !fir.ref<!fir.array<4xi8>>) -> (!fir.ptr<i32>, !fir.ptr<i32>)
+! HLFIR:           %[[VAL_10:.*]]:2 = hlfir.declare %[[VAL_9]] storage(%[[VAL_6]][0]) uniq_name("_QFtest3Ej1") fortran_attrs<internal_assoc> : (!fir.ptr<i32>, !fir.ref<!fir.array<4xi8>>) -> (!fir.ptr<i32>, !fir.ptr<i32>)
 ! HLFIR:           %[[VAL_11:.*]] = fir.convert %[[VAL_0]] : (!fir.ref<tuple<i32>>) -> !fir.ref<!fir.array<4xi8>>
 ! HLFIR:           %[[VAL_12:.*]] = arith.constant 0 : index
 ! HLFIR:           %[[VAL_13:.*]] = fir.coordinate_of %[[VAL_11]], %[[VAL_12]] : (!fir.ref<!fir.array<4xi8>>, index) -> !fir.ref<i8>
 ! HLFIR:           %[[VAL_14:.*]] = fir.convert %[[VAL_13]] : (!fir.ref<i8>) -> !fir.ptr<i32>
-! HLFIR:           %[[VAL_15:.*]]:2 = hlfir.declare %[[VAL_14]] storage(%[[VAL_11]][0]) uniq_name("_QFtest3Ek1") : (!fir.ptr<i32>, !fir.ref<!fir.array<4xi8>>) -> (!fir.ptr<i32>, !fir.ptr<i32>)
+! HLFIR:           %[[VAL_15:.*]]:2 = hlfir.declare %[[VAL_14]] storage(%[[VAL_11]][0]) uniq_name("_QFtest3Ek1") fortran_attrs<internal_assoc> : (!fir.ptr<i32>, !fir.ref<!fir.array<4xi8>>) -> (!fir.ptr<i32>, !fir.ptr<i32>)
 ! HLFIR:           %[[VAL_16:.*]] = fir.load %[[VAL_10]]#0 : !fir.ptr<i32>
 ! HLFIR:           %[[VAL_17:.*]] = fir.load %[[VAL_15]]#0 : !fir.ptr<i32>
 ! HLFIR:           %[[VAL_18:.*]] = arith.addi %[[VAL_16]], %[[VAL_17]] : i32
@@ -105,17 +105,17 @@ end subroutine test4
 ! HLFIR:           %[[VAL_2:.*]] = arith.constant 0 : index
 ! HLFIR:           %[[VAL_3:.*]] = fir.coordinate_of %[[VAL_1]], %[[VAL_2]] : (!fir.ref<!fir.array<4xi8>>, index) -> !fir.ref<i8>
 ! HLFIR:           %[[VAL_4:.*]] = fir.convert %[[VAL_3]] : (!fir.ref<i8>) -> !fir.ptr<i32>
-! HLFIR:           %[[VAL_5:.*]]:2 = hlfir.declare %[[VAL_4]] storage(%[[VAL_1]][0]) uniq_name("_QFtest4Ei1") : (!fir.ptr<i32>, !fir.ref<!fir.array<4xi8>>) -> (!fir.ptr<i32>, !fir.ptr<i32>)
+! HLFIR:           %[[VAL_5:.*]]:2 = hlfir.declare %[[VAL_4]] storage(%[[VAL_1]][0]) uniq_name("_QFtest4Ei1") fortran_attrs<internal_assoc> : (!fir.ptr<i32>, !fir.ref<!fir.array<4xi8>>) -> (!fir.ptr<i32>, !fir.ptr<i32>)
 ! HLFIR:           %[[VAL_6:.*]] = fir.convert %[[VAL_0]] : (!fir.ref<tuple<i32>>) -> !fir.ref<!fir.array<4xi8>>
 ! HLFIR:           %[[VAL_7:.*]] = arith.constant 0 : index
 ! HLFIR:           %[[VAL_8:.*]] = fir.coordinate_of %[[VAL_6]], %[[VAL_7]] : (!fir.ref<!fir.array<4xi8>>, index) -> !fir.ref<i8>
 ! HLFIR:           %[[VAL_9:.*]] = fir.convert %[[VAL_8]] : (!fir.ref<i8>) -> !fir.ptr<i32>
-! HLFIR:           %[[VAL_10:.*]]:2 = hlfir.declare %[[VAL_9]] storage(%[[VAL_6]][0]) uniq_name("_QFtest4Ej1") : (!fir.ptr<i32>, !fir.ref<!fir.array<4xi8>>) -> (!fir.ptr<i32>, !fir.ptr<i32>)
+! HLFIR:           %[[VAL_10:.*]]:2 = hlfir.declare %[[VAL_9]] storage(%[[VAL_6]][0]) uniq_name("_QFtest4Ej1") fortran_attrs<internal_assoc> : (!fir.ptr<i32>, !fir.ref<!fir.array<4xi8>>) -> (!fir.ptr<i32>, !fir.ptr<i32>)
 ! HLFIR:           %[[VAL_11:.*]] = fir.convert %[[VAL_0]] : (!fir.ref<tuple<i32>>) -> !fir.ref<!fir.array<4xi8>>
 ! HLFIR:           %[[VAL_12:.*]] = arith.constant 0 : index
 ! HLFIR:           %[[VAL_13:.*]] = fir.coordinate_of %[[VAL_11]], %[[VAL_12]] : (!fir.ref<!fir.array<4xi8>>, index) -> !fir.ref<i8>
 ! HLFIR:           %[[VAL_14:.*]] = fir.convert %[[VAL_13]] : (!fir.ref<i8>) -> !fir.ptr<i32>
-! HLFIR:           %[[VAL_15:.*]]:2 = hlfir.declare %[[VAL_14]] storage(%[[VAL_11]][0]) uniq_name("_QFtest4Ek1") : (!fir.ptr<i32>, !fir.ref<!fir.array<4xi8>>) -> (!fir.ptr<i32>, !fir.ptr<i32>)
+! HLFIR:           %[[VAL_15:.*]]:2 = hlfir.declare %[[VAL_14]] storage(%[[VAL_11]][0]) uniq_name("_QFtest4Ek1") fortran_attrs<internal_assoc> : (!fir.ptr<i32>, !fir.ref<!fir.array<4xi8>>) -> (!fir.ptr<i32>, !fir.ptr<i32>)
 ! HLFIR:           %[[VAL_16:.*]] = fir.load %[[VAL_10]]#0 : !fir.ptr<i32>
 ! HLFIR:           %[[VAL_17:.*]] = fir.load %[[VAL_15]]#0 : !fir.ptr<i32>
 ! HLFIR:           %[[VAL_18:.*]] = arith.addi %[[VAL_16]], %[[VAL_17]] : i32
diff --git a/flang/test/Lower/host-associated-globals-licm.f90 b/flang/test/Lower/host-associated-globals-licm.f90
new file mode 100644
index 0000000000000..f1b20b3f2b211
--- /dev/null
+++ b/flang/test/Lower/host-associated-globals-licm.f90
@@ -0,0 +1,96 @@
+! REQUIRES: module-independent
+! RUN: split-file %s %t
+! RUN: %flang_fc1 -fsave-main-program -emit-fir %t/main.f90 -o - | fir-opt --flang-licm | FileCheck %s --check-prefix=MAIN
+! RUN: %flang_fc1 -fno-automatic -emit-fir %t/main.f90 -o - | fir-opt --flang-licm | FileCheck %s --check-prefix=MAIN
+! RUN: %flang_fc1 -emit-fir %t/saved.f90 -o - | fir-opt --flang-licm | FileCheck %s --check-prefix=SAVED
+! RUN: %flang_fc1 -emit-hlfir -module-dir %t %t/controls.f90 -o - | FileCheck %s --check-prefix=CONTROLS
+
+! Check that host globals shared by sibling internal procedures carry
+! internal_assoc. Without it, FIR alias analysis may miss writes by bump(),
+! allowing FIR LICM to hoist loads out of accumulate's loop. Loads must
+! remain after the call for explicit/initialization-implied SAVE and for
+! -fsave-main-program/-fno-automatic. Controls check that unrelated declarations
+! and ordinary host association keep their existing attributes.
+
+! MAIN-LABEL: func.func private @_QFPaccumulate(
+! MAIN: %[[X:[^ ]+]] = fir.declare {{.*}}uniq_name("_QFEx") fortran_attrs<internal_assoc>
+! MAIN: fir.do_loop
+! MAIN-NOT: {{^ *[}]}}
+! MAIN: fir.call @_QFPbump(
+! MAIN-NOT: {{^ *[}]}}
+! MAIN: fir.load %[[X]] :
+! MAIN: {{^ *[}]}}
+!--- main.f90
+program p
+  integer :: x
+  x=0
+  call accumulate()
+contains
+  subroutine accumulate()
+    integer :: i,s
+    s=0
+    do i=1,3
+      call bump()
+      s=s+x
+    end do
+    print *,s
+  end subroutine
+  subroutine bump()
+    x=x+1
+  end subroutine
+end program
+! SAVED-LABEL: func.func private @_QFsavedPaccumulate(
+! SAVED-DAG: %[[X:[^ ]+]] = fir.declare {{.*}}uniq_name("_QFsavedEx") fortran_attrs<internal_assoc>
+! SAVED-DAG: %[[Y:[^ ]+]] = fir.declare {{.*}}uniq_name("_QFsavedEy") fortran_attrs<internal_assoc>
+! SAVED: fir.do_loop
+! SAVED-NOT: {{^ *[}]}}
+! SAVED: fir.call @_QFsavedPbump(
+! SAVED-NOT: {{^ *[}]}}
+! SAVED: fir.load %[[X]] :
+! SAVED-NOT: {{^ *[}]}}
+! SAVED: fir.load %[[Y]] :
+! SAVED: {{^ *[}]}}
+!--- saved.f90
+subroutine saved()
+  integer, save :: x
+  integer :: y=0
+  x=0
+  y=0
+  call accumulate()
+contains
+  subroutine accumulate()
+    integer :: i,s
+    s=0
+    do i=1,3
+      call bump()
+      s=s+x+y
+    end do
+    print *,s
+  end subroutine
+  subroutine bump()
+    x=x+1
+    y=y+1
+  end subroutine
+end subroutine
+! CONTROLS-LABEL: func.func @_QPcontrols(
+! CONTROLS: hlfir.declare {{.*}}uniq_name("_QFcontrolsEuncaptured") :
+! CONTROLS-LABEL: func.func private @_QFcontrolsPinner(
+! CONTROLS-DAG: hlfir.declare {{.*}}uniq_name("_QMglobalsEx") :
+! CONTROLS-DAG: hlfir.declare {{.*}}uniq_name("_QFcontrolsElocal") fortran_attrs<host_assoc>
+!--- controls.f90
+module globals
+  integer :: x
+end module
+subroutine controls()
+  use globals
+  integer, save :: uncaptured
+  integer :: local
+  uncaptured=1
+  local=2
+  call inner()
+  print *,uncaptured
+contains
+  subroutine inner()
+    print *,local,x
+  end subroutine
+end subroutine
diff --git a/flang/test/Lower/host-associated-globals.f90 b/flang/test/Lower/host-associated-globals.f90
index 6d87d91516db0..d7b84f56f52d0 100644
--- a/flang/test/Lower/host-associated-globals.f90
+++ b/flang/test/Lower/host-associated-globals.f90
@@ -44,11 +44,11 @@ subroutine bar()
 ! CHECK:  %[[VAL_2:.*]] = arith.constant 4 : index
 ! CHECK:  %[[VAL_3:.*]] = fir.coordinate_of %[[VAL_0]], %[[VAL_2]] : (!fir.ref<!fir.array<12xi8>>, index) -> !fir.ref<i8>
 ! CHECK:  %[[VAL_4:.*]] = fir.convert %[[VAL_3]] : (!fir.ref<i8>) -> !fir.ptr<i32>
-! CHECK:  %{{.*}}:2 = hlfir.declare %[[VAL_4]] storage(%[[VAL_0]][4]) uniq_name("_QFtest_commonEj_in_equiv") : (!fir.ptr<i32>, !fir.ref<!fir.array<12xi8>>) -> (!fir.ptr<i32>, !fir.ptr<i32>)
+! CHECK:  %{{.*}}:2 = hlfir.declare %[[VAL_4]] storage(%[[VAL_0]][4]) uniq_name("_QFtest_commonEj_in_equiv") fortran_attrs<internal_assoc> : (!fir.ptr<i32>, !fir.ref<!fir.array<12xi8>>) -> (!fir.ptr<i32>, !fir.ptr<i32>)
 ! CHECK:  %[[VAL_6:.*]] = arith.constant 8 : index
 ! CHECK:  %[[VAL_7:.*]] = fir.coordinate_of %[[VAL_0]], %[[VAL_6]] : (!fir.ref<!fir.array<12xi8>>, index) -> !fir.ref<i8>
 ! CHECK:  %[[VAL_8:.*]] = fir.convert %[[VAL_7]] : (!fir.ref<i8>) -> !fir.ref<i32>
-! CHECK:  %{{.*}}:2 = hlfir.declare %[[VAL_8]] storage(%[[VAL_0]][8]) uniq_name("_QFtest_commonEnot_in_equiv") : (!fir.ref<i32>, !fir.ref<!fir.array<12xi8>>) -> (!fir.ref<i32>, !fir.ref<i32>)
+! CHECK:  %{{.*}}:2 = hlfir.declare %[[VAL_8]] storage(%[[VAL_0]][8]) uniq_name("_QFtest_commonEnot_in_equiv") fortran_attrs<internal_assoc> : (!fir.ref<i32>, !fir.ref<!fir.array<12xi8>>) -> (!fir.ref<i32>, !fir.ref<i32>)
 
 subroutine saved_equiv()
   integer, save :: i(2)
@@ -66,9 +66,9 @@ subroutine bar()
 ! CHECK:  %[[VAL_1:.*]] = arith.constant 4 : index
 ! CHECK:  %[[VAL_2:.*]] = fir.coordinate_of %[[VAL_0]], %[[VAL_1]] : (!fir.ref<!fir.array<8xi8>>, index) -> !fir.ref<i8>
 ! CHECK:  %[[VAL_3:.*]] = fir.convert %[[VAL_2]] : (!fir.ref<i8>) -> !fir.ptr<i32>
-! CHECK:  %{{.*}}:2 = hlfir.declare %[[VAL_3]] storage(%[[VAL_0]][4]) uniq_name("_QFsaved_equivEj_in_equiv") : (!fir.ptr<i32>, !fir.ref<!fir.array<8xi8>>) -> (!fir.ptr<i32>, !fir.ptr<i32>)
+! CHECK:  %{{.*}}:2 = hlfir.declare %[[VAL_3]] storage(%[[VAL_0]][4]) uniq_name("_QFsaved_equivEj_in_equiv") fortran_attrs<internal_assoc> : (!fir.ptr<i32>, !fir.ref<!fir.array<8xi8>>) -> (!fir.ptr<i32>, !fir.ptr<i32>)
 ! CHECK:  %[[VAL_4:.*]] = fir.address_of(@_QFsaved_equivEnot_in_equiv) : !fir.ref<i32>
-! CHECK:  %{{.*}}:2 = hlfir.declare %[[VAL_4]] uniq_name("_QFsaved_equivEnot_in_equiv") : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+! CHECK:  %{{.*}}:2 = hlfir.declare %[[VAL_4]] uniq_name("_QFsaved_equivEnot_in_equiv") fortran_attrs<internal_assoc> : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
 
 subroutine mixed_capture()
   integer, save :: saved_i
@@ -89,7 +89,7 @@ subroutine bar()
 ! CHECK:  %[[VAL_2:.*]] = arith.constant 0 : index
 ! CHECK:  %[[VAL_3:.*]] = fir.coordinate_of %[[VAL_1]], %[[VAL_2]] : (!fir.ref<!fir.array<4xi8>>, index) -> !fir.ref<i8>
 ! CHECK:  %[[VAL_4:.*]] = fir.convert %[[VAL_3]] : (!fir.ref<i8>) -> !fir.ptr<i32>
-! CHECK:  %[[VAL_declare_saved_j:.*]]:2 = hlfir.declare %[[VAL_4]] storage(%[[VAL_1]][0]) uniq_name("_QFmixed_captureEsaved_j") : (!fir.ptr<i32>, !fir.ref<!fir.array<4xi8>>) -> (!fir.ptr<i32>, !fir.ptr<i32>)
+! CHECK:  %[[VAL_declare_saved_j:.*]]:2 = hlfir.declare %[[VAL_4]] storage(%[[VAL_1]][0]) uniq_name("_QFmixed_captureEsaved_j") fortran_attrs<internal_assoc> : (!fir.ptr<i32>, !fir.ref<!fir.array<4xi8>>) -> (!fir.ptr<i32>, !fir.ptr<i32>)
 ! CHECK:  %[[VAL_5:.*]] = arith.constant 0 : i32
 ! CHECK:  %[[VAL_6:.*]] = fir.coordinate_of %[[VAL_0]], %[[VAL_5]] : (!fir.ref<tuple<!fir.ref<i32>>>, i32) -> !fir.llvm_ptr<!fir.ref<i32>>
 ! CHECK:  %[[VAL_7:.*]] = fir.load %[[VAL_6]] : !fir.llvm_ptr<!fir.ref<i32>>
diff --git a/flang/test/Lower/volatile4.f90 b/flang/test/Lower/volatile4.f90
index 2f8ac98ee27da..62f60028e3fde 100644
--- a/flang/test/Lower/volatile4.f90
+++ b/flang/test/Lower/volatile4.f90
@@ -60,13 +60,13 @@ subroutine host_assoc
 ! CHECK:           %[[ADDRESS_OF_0:.*]] = fir.address_of(@_QFEarr) : !fir.ref<!fir.array<10xi32>>
 ! CHECK:           %[[SHAPE_0:.*]] = fir.shape %[[CONSTANT_2]] : (index) -> !fir.shape<1>
 ! CHECK:           %[[VOLATILE_CAST_0:.*]] = fir.volatile_cast %[[ADDRESS_OF_0]] : (!fir.ref<!fir.array<10xi32>>) -> !fir.ref<!fir.array<10xi32>, volatile>
-! CHECK:           %[[DECLARE_0:.*]]:2 = hlfir.declare %[[VOLATILE_CAST_0]](%[[SHAPE_0]]) uniq_name("_QFEarr") fortran_attrs<volatile> : (!fir.ref<!fir.array<10xi32>, volatile>, !fir.shape<1>) -> (!fir.ref<!fir.array<10xi32>, volatile>, !fir.ref<!fir.array<10xi32>, volatile>)
+! CHECK:           %[[DECLARE_0:.*]]:2 = hlfir.declare %[[VOLATILE_CAST_0]](%[[SHAPE_0]]) uniq_name("_QFEarr") fortran_attrs<volatile, internal_assoc> : (!fir.ref<!fir.array<10xi32>, volatile>, !fir.shape<1>) -> (!fir.ref<!fir.array<10xi32>, volatile>, !fir.ref<!fir.array<10xi32>, volatile>)
 ! CHECK:           %[[ADDRESS_OF_1:.*]] = fir.address_of(@_QFEptr) : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>
 ! CHECK:           %[[VOLATILE_CAST_1:.*]] = fir.volatile_cast %[[ADDRESS_OF_1]] : (!fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>) -> !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>, volatile>, volatile>
-! CHECK:           %[[DECLARE_1:.*]]:2 = hlfir.declare %[[VOLATILE_CAST_1]] uniq_name("_QFEptr") fortran_attrs<pointer, volatile> : (!fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>, volatile>, volatile>) -> (!fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>, volatile>, volatile>, !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>, volatile>, volatile>)
+! CHECK:           %[[DECLARE_1:.*]]:2 = hlfir.declare %[[VOLATILE_CAST_1]] uniq_name("_QFEptr") fortran_attrs<pointer, volatile, internal_assoc> : (!fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>, volatile>, volatile>) -> (!fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>, volatile>, volatile>, !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>, volatile>, volatile>)
 ! CHECK:           %[[ADDRESS_OF_2:.*]] = fir.address_of(@_QFEtgt) : !fir.ref<!fir.array<10xi32>>
 ! CHECK:           %[[VOLATILE_CAST_2:.*]] = fir.volatile_cast %[[ADDRESS_OF_2]] : (!fir.ref<!fir.array<10xi32>>) -> !fir.ref<!fir.array<10xi32>, volatile>
-! CHECK:           %[[DECLARE_2:.*]]:2 = hlfir.declare %[[VOLATILE_CAST_2]](%[[SHAPE_0]]) uniq_name("_QFEtgt") fortran_attrs<target, volatile> : (!fir.ref<!fir.array<10xi32>, volatile>, !fir.shape<1>) -> (!fir.ref<!fir.array<10xi32>, volatile>, !fir.ref<!fir.array<10xi32>, volatile>)
+! CHECK:           %[[DECLARE_2:.*]]:2 = hlfir.declare %[[VOLATILE_CAST_2]](%[[SHAPE_0]]) uniq_name("_QFEtgt") fortran_attrs<target, volatile, internal_assoc> : (!fir.ref<!fir.array<10xi32>, volatile>, !fir.shape<1>) -> (!fir.ref<!fir.array<10xi32>, volatile>, !fir.ref<!fir.array<10xi32>, volatile>)
 ! CHECK:           %[[COORDINATE_OF_0:.*]] = fir.coordinate_of %[[ARG0]], %[[CONSTANT_1]] : (!fir.ref<tuple<!fir.ref<i32>>>, i32) -> !fir.llvm_ptr<!fir.ref<i32>>
 ! CHECK:           %[[LOAD_0:.*]] = fir.load %[[COORDINATE_OF_0]] : !fir.llvm_ptr<!fir.ref<i32>>
 ! CHECK:           %[[VOLATILE_CAST_3:.*]] = fir.volatile_cast %[[LOAD_0]] : (!fir.ref<i32>) -> !fir.ref<i32, volatile>



More information about the flang-commits mailing list