[flang-commits] [flang] [flang] Access host associated equivalences via global aggregate storage. (PR #67078)

via flang-commits flang-commits at lists.llvm.org
Thu Sep 21 17:50:21 PDT 2023


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

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

<details>
<summary>Changes</summary>

Example:
```
subroutine global_sub()
  integer, dimension(4) :: iarr4=(/1,2,3,4/)
  integer, dimension(4) :: jarr4
  equivalence(iarr4,jarr4)
  call sub1
  print *, iarr4
contains
  subroutine sub1
    iarr4=jarr4((/4:1:-1/))
  end subroutine sub1
end subroutine global_sub
```

`iarr4` and `jarr4` are equivalenced via a global aggregate storage,
but the references inside `sub1` are lowered differently.
`iarr4` is accessed via the global aggregate storage, while `jarr4`
is accessed via the argument tuple. This confuses the FIR alias analysis,
that claims that a host associated entity cannot alias with a global
(if they have different source and do not have Target/Pointer
attributes deduced by the alias analysis).

I am not convinced that there is an issue in the alias analysis yet.
I think we'd better lower the accesses uniformly, i.e. if one variable
from an equivalence is lowered via the global aggregate storage, then
any other variable from this equivalence should be lowered the same way
(even if they are used via host association). This patch tries to make
the lowering consistent.

Note that in the above example `iarr4` symbol is global, while
`jarr4` is not. Maybe this issue could have been fixed before
the lowering by uniformly marking all symbols from the equivalence
as globals, so comments are very welcome.


---
Full diff: https://github.com/llvm/llvm-project/pull/67078.diff


2 Files Affected:

- (modified) flang/lib/Lower/HostAssociations.cpp (+31-6) 
- (added) flang/test/Lower/equivalence-with-host-assoc.f90 (+140) 


``````````diff
diff --git a/flang/lib/Lower/HostAssociations.cpp b/flang/lib/Lower/HostAssociations.cpp
index aa0cc50b6347aec..8576639c04807a9 100644
--- a/flang/lib/Lower/HostAssociations.cpp
+++ b/flang/lib/Lower/HostAssociations.cpp
@@ -507,13 +507,38 @@ void Fortran::lower::HostAssociations::addSymbolsToBind(
   assert(tupleSymbols.empty() && globalSymbols.empty() &&
          "must be initially empty");
   this->hostScope = &hostScope;
+
+  // Collect integer offsets of all global aggregate storages
+  // in the host scope.
+  llvm::DenseSet<std::size_t> globalAggregateStoreOffests;
+  for (auto &hostVariable : pft::getScopeVariableList(hostScope))
+    if (hostVariable.isAggregateStore() && hostVariable.isGlobal())
+      globalAggregateStoreOffests.insert(
+          hostVariable.getAggregateStore().getOffset());
+
+  // Look for aliases (EQUIVALENCE variables) that are associated
+  // with the global aggregate storages in the host scope.
+  // If such an alias is referenced by the internal procedure,
+  // its symbol might not be global, but we'd rather access
+  // it via the global aggregate storage than via the argument tuple.
+  for (auto &hostVariable : pft::getScopeVariableList(hostScope))
+    if (hostVariable.hasSymbol() && hostVariable.isAlias() &&
+        globalAggregateStoreOffests.contains(hostVariable.getAliasOffset())) {
+      const Fortran::semantics::Symbol *sym =
+          &hostVariable.getSymbol().GetUltimate();
+      if (symbols.contains(sym))
+        globalSymbols.insert(sym);
+    }
+
   for (const auto *s : symbols)
-    if (Fortran::lower::symbolIsGlobal(*s))
-      // The ultimate symbol is stored here so that global symbols from the
-      // host scope can later be searched in this set.
-      globalSymbols.insert(&s->GetUltimate());
-    else
-      tupleSymbols.insert(s);
+    if (!globalSymbols.contains(&s->GetUltimate())) {
+      if (Fortran::lower::symbolIsGlobal(*s))
+        // The ultimate symbol is stored here so that global symbols from the
+        // host scope can later be searched in this set.
+        globalSymbols.insert(&s->GetUltimate());
+      else
+        tupleSymbols.insert(s);
+    }
 }
 
 void Fortran::lower::HostAssociations::hostProcedureBindings(
diff --git a/flang/test/Lower/equivalence-with-host-assoc.f90 b/flang/test/Lower/equivalence-with-host-assoc.f90
new file mode 100644
index 000000000000000..f9ac2692fd9c8a3
--- /dev/null
+++ b/flang/test/Lower/equivalence-with-host-assoc.f90
@@ -0,0 +1,140 @@
+! RUN: bbc -emit-fir -o - %s | FileCheck %s --check-prefixes=FIR
+! RUN: bbc -emit-hlfir -o - %s | FileCheck %s --check-prefixes=HLFIR
+
+subroutine test1()
+  integer :: i1 = 1
+  integer :: j1
+  equivalence(i1,j1)
+contains
+  subroutine inner
+    i1 = j1
+  end subroutine inner
+end subroutine test1
+! FIR-LABEL:   func.func @_QFtest1Pinner() attributes {fir.internal_proc} {
+! FIR:           %[[VAL_0:.*]] = fir.address_of(@_QFtest1Ei1) : !fir.ref<!fir.array<1xi32>>
+! FIR:           %[[VAL_1:.*]] = fir.convert %[[VAL_0]] : (!fir.ref<!fir.array<1xi32>>) -> !fir.ref<!fir.array<4xi8>>
+! FIR:           %[[VAL_2:.*]] = arith.constant 0 : index
+! FIR:           %[[VAL_3:.*]] = fir.coordinate_of %[[VAL_1]], %[[VAL_2]] : (!fir.ref<!fir.array<4xi8>>, index) -> !fir.ref<i8>
+! FIR:           %[[VAL_4:.*]] = fir.convert %[[VAL_3]] : (!fir.ref<i8>) -> !fir.ptr<i32>
+! FIR:           %[[VAL_5:.*]] = arith.constant 0 : index
+! FIR:           %[[VAL_6:.*]] = fir.coordinate_of %[[VAL_1]], %[[VAL_5]] : (!fir.ref<!fir.array<4xi8>>, index) -> !fir.ref<i8>
+! FIR:           %[[VAL_7:.*]] = fir.convert %[[VAL_6]] : (!fir.ref<i8>) -> !fir.ptr<i32>
+! FIR:           %[[VAL_8:.*]] = fir.load %[[VAL_7]] : !fir.ptr<i32>
+! FIR:           fir.store %[[VAL_8]] to %[[VAL_4]] : !fir.ptr<i32>
+! FIR:           return
+! FIR:         }
+
+! HLFIR-LABEL:   func.func @_QFtest1Pinner() attributes {fir.internal_proc} {
+! HLFIR:           %[[VAL_0:.*]] = fir.address_of(@_QFtest1Ei1) : !fir.ref<!fir.array<1xi32>>
+! HLFIR:           %[[VAL_1:.*]] = fir.convert %[[VAL_0]] : (!fir.ref<!fir.array<1xi32>>) -> !fir.ref<!fir.array<4xi8>>
+! 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]] {uniq_name = "_QFtest1Ei1"} : (!fir.ptr<i32>) -> (!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]] {uniq_name = "_QFtest1Ej1"} : (!fir.ptr<i32>) -> (!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
+! HLFIR:         }
+
+module test2
+  real :: f1, f2
+  equivalence(f1, f2)
+contains
+  subroutine host
+    real :: f1 = 1
+    real :: f2
+    equivalence(f1, f2)
+  contains
+    subroutine inner
+      f1 = f2
+    end subroutine inner
+  end subroutine host
+end module test2
+! FIR-LABEL:   func.func @_QMtest2FhostPinner() attributes {fir.internal_proc} {
+! FIR:           %[[VAL_0:.*]] = fir.address_of(@_QMtest2FhostEf1) : !fir.ref<!fir.array<1xi32>>
+! FIR:           %[[VAL_1:.*]] = fir.convert %[[VAL_0]] : (!fir.ref<!fir.array<1xi32>>) -> !fir.ref<!fir.array<4xi8>>
+! FIR:           %[[VAL_2:.*]] = arith.constant 0 : index
+! FIR:           %[[VAL_3:.*]] = fir.coordinate_of %[[VAL_1]], %[[VAL_2]] : (!fir.ref<!fir.array<4xi8>>, index) -> !fir.ref<i8>
+! FIR:           %[[VAL_4:.*]] = fir.convert %[[VAL_3]] : (!fir.ref<i8>) -> !fir.ptr<f32>
+! FIR:           %[[VAL_5:.*]] = arith.constant 0 : index
+! FIR:           %[[VAL_6:.*]] = fir.coordinate_of %[[VAL_1]], %[[VAL_5]] : (!fir.ref<!fir.array<4xi8>>, index) -> !fir.ref<i8>
+! FIR:           %[[VAL_7:.*]] = fir.convert %[[VAL_6]] : (!fir.ref<i8>) -> !fir.ptr<f32>
+! FIR:           %[[VAL_8:.*]] = fir.load %[[VAL_7]] : !fir.ptr<f32>
+! FIR:           fir.store %[[VAL_8]] to %[[VAL_4]] : !fir.ptr<f32>
+! FIR:           return
+! FIR:         }
+
+! HLFIR-LABEL:   func.func @_QMtest2FhostPinner() attributes {fir.internal_proc} {
+! HLFIR:           %[[VAL_0:.*]] = fir.address_of(@_QMtest2FhostEf1) : !fir.ref<!fir.array<1xi32>>
+! HLFIR:           %[[VAL_1:.*]] = fir.convert %[[VAL_0]] : (!fir.ref<!fir.array<1xi32>>) -> !fir.ref<!fir.array<4xi8>>
+! 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]] {uniq_name = "_QMtest2FhostEf1"} : (!fir.ptr<f32>) -> (!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]] {uniq_name = "_QMtest2FhostEf2"} : (!fir.ptr<f32>) -> (!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
+! HLFIR:         }
+
+subroutine test3()
+  integer :: i1 = 1
+  integer :: j1, k1
+  common /blk/ k1
+  equivalence(i1,j1,k1)
+contains
+  subroutine inner
+    i1 = j1 + k1
+  end subroutine inner
+end subroutine test3
+! FIR-LABEL:   func.func @_QFtest3Pinner() attributes {fir.internal_proc} {
+! FIR:           %[[VAL_0:.*]] = fir.address_of(@blk_) : !fir.ref<tuple<i32>>
+! FIR:           %[[VAL_1:.*]] = fir.convert %[[VAL_0]] : (!fir.ref<tuple<i32>>) -> !fir.ref<!fir.array<?xi8>>
+! FIR:           %[[VAL_2:.*]] = arith.constant 0 : index
+! FIR:           %[[VAL_3:.*]] = fir.coordinate_of %[[VAL_1]], %[[VAL_2]] : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
+! FIR:           %[[VAL_4:.*]] = fir.convert %[[VAL_3]] : (!fir.ref<i8>) -> !fir.ptr<i32>
+! FIR:           %[[VAL_5:.*]] = fir.convert %[[VAL_0]] : (!fir.ref<tuple<i32>>) -> !fir.ref<!fir.array<?xi8>>
+! FIR:           %[[VAL_6:.*]] = arith.constant 0 : index
+! FIR:           %[[VAL_7:.*]] = fir.coordinate_of %[[VAL_5]], %[[VAL_6]] : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
+! FIR:           %[[VAL_8:.*]] = fir.convert %[[VAL_7]] : (!fir.ref<i8>) -> !fir.ptr<i32>
+! FIR:           %[[VAL_9:.*]] = fir.convert %[[VAL_0]] : (!fir.ref<tuple<i32>>) -> !fir.ref<!fir.array<?xi8>>
+! FIR:           %[[VAL_10:.*]] = arith.constant 0 : index
+! FIR:           %[[VAL_11:.*]] = fir.coordinate_of %[[VAL_9]], %[[VAL_10]] : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
+! FIR:           %[[VAL_12:.*]] = fir.convert %[[VAL_11]] : (!fir.ref<i8>) -> !fir.ptr<i32>
+! FIR:           %[[VAL_13:.*]] = fir.load %[[VAL_8]] : !fir.ptr<i32>
+! FIR:           %[[VAL_14:.*]] = fir.load %[[VAL_12]] : !fir.ptr<i32>
+! FIR:           %[[VAL_15:.*]] = arith.addi %[[VAL_13]], %[[VAL_14]] : i32
+! FIR:           fir.store %[[VAL_15]] to %[[VAL_4]] : !fir.ptr<i32>
+! FIR:           return
+! FIR:         }
+
+! HLFIR-LABEL:   func.func @_QFtest3Pinner() attributes {fir.internal_proc} {
+! HLFIR:           %[[VAL_0:.*]] = fir.address_of(@blk_) : !fir.ref<tuple<i32>>
+! HLFIR:           %[[VAL_1:.*]] = fir.convert %[[VAL_0]] : (!fir.ref<tuple<i32>>) -> !fir.ref<!fir.array<?xi8>>
+! HLFIR:           %[[VAL_2:.*]] = arith.constant 0 : index
+! HLFIR:           %[[VAL_3:.*]] = fir.coordinate_of %[[VAL_1]], %[[VAL_2]] : (!fir.ref<!fir.array<?xi8>>, 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]] {uniq_name = "_QFtest3Ei1"} : (!fir.ptr<i32>) -> (!fir.ptr<i32>, !fir.ptr<i32>)
+! HLFIR:           %[[VAL_6:.*]] = fir.convert %[[VAL_0]] : (!fir.ref<tuple<i32>>) -> !fir.ref<!fir.array<?xi8>>
+! HLFIR:           %[[VAL_7:.*]] = arith.constant 0 : index
+! HLFIR:           %[[VAL_8:.*]] = fir.coordinate_of %[[VAL_6]], %[[VAL_7]] : (!fir.ref<!fir.array<?xi8>>, 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]] {uniq_name = "_QFtest3Ej1"} : (!fir.ptr<i32>) -> (!fir.ptr<i32>, !fir.ptr<i32>)
+! HLFIR:           %[[VAL_11:.*]] = fir.convert %[[VAL_0]] : (!fir.ref<tuple<i32>>) -> !fir.ref<!fir.array<?xi8>>
+! HLFIR:           %[[VAL_12:.*]] = arith.constant 0 : index
+! HLFIR:           %[[VAL_13:.*]] = fir.coordinate_of %[[VAL_11]], %[[VAL_12]] : (!fir.ref<!fir.array<?xi8>>, 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]] {uniq_name = "_QFtest3Ek1"} : (!fir.ptr<i32>) -> (!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
+! HLFIR:           hlfir.assign %[[VAL_18]] to %[[VAL_5]]#0 : i32, !fir.ptr<i32>
+! HLFIR:           return
+! HLFIR:         }

``````````

</details>


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


More information about the flang-commits mailing list