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

via flang-commits flang-commits at lists.llvm.org
Mon Oct 19 06:52:12 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-flang-fir-hlfir

Author: Sergey Shcherbinin (SergeyShch01)

<details>
<summary>Changes</summary>

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.


---

Patch is 29.87 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/233433.diff


12 Files Affected:

- (modified) flang/include/flang/Lower/HostAssociations.h (+5) 
- (modified) flang/include/flang/Optimizer/Dialect/FIRAttr.td (+1-1) 
- (modified) flang/lib/Lower/ConvertVariable.cpp (+13-1) 
- (modified) flang/test/Lower/MIF/coarray_alloc_many_declare.f90 (+1-1) 
- (added) flang/test/Lower/OpenMP/host-associated-globals-private.f90 (+39) 
- (modified) flang/test/Lower/OpenMP/threadprivate-host-association-2.f90 (+3-3) 
- (modified) flang/test/Lower/OpenMP/threadprivate-host-association-3.f90 (+3-3) 
- (modified) flang/test/Lower/OpenMP/threadprivate-host-association.f90 (+3-3) 
- (modified) flang/test/Lower/equivalence-with-host-assoc.f90 (+10-10) 
- (added) flang/test/Lower/host-associated-globals-licm.f90 (+96) 
- (modified) flang/test/Lower/host-associated-globals.f90 (+5-5) 
- (modified) flang/test/Lower/volatile4.f90 (+3-3) 


``````````diff
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-...
[truncated]

``````````

</details>


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


More information about the flang-commits mailing list