[flang-commits] [flang] [flang] AliasAnalysis: Handle fir.load on hlfir.designate (PR #127107)

Joel E. Denny via flang-commits flang-commits at lists.llvm.org
Mon Feb 17 12:57:29 PST 2025


https://github.com/jdenny-ornl updated https://github.com/llvm/llvm-project/pull/127107

>From 201fa499e9ea1ea7c4407d9e4514e37105b41db6 Mon Sep 17 00:00:00 2001
From: "Joel E. Denny" <jdenny.ornl at gmail.com>
Date: Thu, 13 Feb 2025 13:32:13 -0500
Subject: [PATCH 1/2] [flang] AliasAnalysis: Handle fir.load on hlfir.designate

For example, determine that the address in `obj%p` below cannot alias
the address of `v`:

```
module m
  type :: ty
    real, pointer :: p
  end type ty
end module m
subroutine test()
  use m
  real, target :: t
  real :: v
  type(ty) :: obj
  obj%p => t
  v = obj%p
end subroutine test
```
---
 .../flang/Optimizer/Analysis/AliasAnalysis.h  |   8 +-
 .../lib/Optimizer/Analysis/AliasAnalysis.cpp  |  18 +-
 .../AliasAnalysis/load-ptr-designate.fir      | 484 ++++++++++++++++++
 3 files changed, 504 insertions(+), 6 deletions(-)
 create mode 100644 flang/test/Analysis/AliasAnalysis/load-ptr-designate.fir

diff --git a/flang/include/flang/Optimizer/Analysis/AliasAnalysis.h b/flang/include/flang/Optimizer/Analysis/AliasAnalysis.h
index 8d17e4e476d10..c71988d081dd0 100644
--- a/flang/include/flang/Optimizer/Analysis/AliasAnalysis.h
+++ b/flang/include/flang/Optimizer/Analysis/AliasAnalysis.h
@@ -211,14 +211,14 @@ struct AliasAnalysis {
   fir::AliasAnalysis::Source getSource(mlir::Value,
                                        bool getLastInstantiationPoint = false);
 
+  /// Return true, if `ty` is a reference type to a boxed
+  /// POINTER object or a raw fir::PointerType.
+  static bool isPointerReference(mlir::Type ty);
+
 private:
   /// Return true, if `ty` is a reference type to an object of derived type
   /// that contains a component with POINTER attribute.
   static bool isRecordWithPointerComponent(mlir::Type ty);
-
-  /// Return true, if `ty` is a reference type to a boxed
-  /// POINTER object or a raw fir::PointerType.
-  static bool isPointerReference(mlir::Type ty);
 };
 
 inline bool operator==(const AliasAnalysis::Source::SourceOrigin &lhs,
diff --git a/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp b/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp
index 873758487ddd0..70fa18ad65b9b 100644
--- a/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp
+++ b/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp
@@ -54,10 +54,11 @@ static bool hasGlobalOpTargetAttr(mlir::Value v, fir::AddrOfOp op) {
 static mlir::Value
 getOriginalDef(mlir::Value v,
                fir::AliasAnalysis::Source::Attributes &attributes,
-               bool &isCapturedInInternalProcedure) {
+               bool &isCapturedInInternalProcedure, bool &approximateSource) {
   mlir::Operation *defOp;
   bool breakFromLoop = false;
   while (!breakFromLoop && (defOp = v.getDefiningOp())) {
+    mlir::Type ty = defOp->getResultTypes()[0];
     llvm::TypeSwitch<Operation *>(defOp)
         .Case<fir::ConvertOp>([&](fir::ConvertOp op) { v = op.getValue(); })
         .Case<fir::DeclareOp, hlfir::DeclareOp>([&](auto op) {
@@ -67,6 +68,18 @@ getOriginalDef(mlir::Value v,
           isCapturedInInternalProcedure |=
               varIf.isCapturedInInternalProcedure();
         })
+        .Case<fir::CoordinateOp>([&](auto op) {
+          if (fir::AliasAnalysis::isPointerReference(ty))
+            attributes.set(fir::AliasAnalysis::Attribute::Pointer);
+          v = op->getOperand(0);
+          approximateSource = true;
+        })
+        .Case<hlfir::DesignateOp>([&](hlfir::DesignateOp op) {
+          auto varIf = llvm::cast<fir::FortranVariableOpInterface>(defOp);
+          attributes |= getAttrsFromVariable(varIf);
+          v = op.getMemref();
+          approximateSource = true;
+        })
         .Default([&](auto op) { breakFromLoop = true; });
   }
   return v;
@@ -609,7 +622,8 @@ AliasAnalysis::Source AliasAnalysis::getSource(mlir::Value v,
               attributes.set(Attribute::Pointer);
 
             auto def = getOriginalDef(op.getMemref(), attributes,
-                                      isCapturedInInternalProcedure);
+                                      isCapturedInInternalProcedure,
+                                      approximateSource);
             if (auto addrOfOp = def.template getDefiningOp<fir::AddrOfOp>()) {
               global = addrOfOp.getSymbol();
 
diff --git a/flang/test/Analysis/AliasAnalysis/load-ptr-designate.fir b/flang/test/Analysis/AliasAnalysis/load-ptr-designate.fir
new file mode 100644
index 0000000000000..192de7f96f928
--- /dev/null
+++ b/flang/test/Analysis/AliasAnalysis/load-ptr-designate.fir
@@ -0,0 +1,484 @@
+// Check aliasing with the address *in* (not *of*) a pointer component
+// (hlfir.designate).
+//
+// Throughout this test, the ".fir" suffix on symbols indicates a version of the
+// MLIR after convert-hlfir-to-fir.  A key difference is that component access
+// is via fir.coordinate_of instead of hlfir.designate.  We would like alias
+// analysis results to be the same in both versions.
+
+// RUN: fir-opt %s -split-input-file -o /dev/null --mlir-disable-threading  \
+// RUN:   -pass-pipeline='builtin.module(func.func(test-fir-alias-analysis))' \
+// RUN:   2>&1 | FileCheck -match-full-lines %s
+
+// module m
+//   type :: ty
+//     real, pointer :: p0, p1
+//     real :: arr(2)
+//     real, allocatable :: alloc
+//     ! target attribute on components is not supported
+//   end type ty
+// end module m
+// subroutine test()
+//   use m
+//   real, target :: t
+//   real :: v
+//   type(ty) :: obj
+//   type(ty), target :: t_obj
+// end subroutine test
+
+// CHECK-LABEL: Testing : "_QPtest"
+
+// The address in a pointer can alias the address in another pointer or the
+// address of a target but not the address of other variables.
+// CHECK-DAG: obj%p0.tgt#0 <-> obj%p1.tgt#0: MayAlias
+// CHECK-DAG: t#0 <-> obj%p0.tgt#0: MayAlias
+// CHECK-DAG: t#0 <-> obj%p1.tgt#0: MayAlias
+// CHECK-DAG: v#0 <-> obj%p0.tgt#0: NoAlias
+// CHECK-DAG: v#0 <-> obj%p1.tgt#0: NoAlias
+// CHECK-DAG: obj%p0.tgt.fir#0 <-> obj%p1.tgt.fir#0: MayAlias
+// CHECK-DAG: t.fir#0 <-> obj%p0.tgt.fir#0: MayAlias
+// CHECK-DAG: t.fir#0 <-> obj%p1.tgt.fir#0: MayAlias
+// CHECK-DAG: v.fir#0 <-> obj%p0.tgt.fir#0: NoAlias
+// CHECK-DAG: v.fir#0 <-> obj%p1.tgt.fir#0: NoAlias
+
+// The address in a pointer cannot alias the address of a pointer.
+// CHECK-DAG: obj%p0#0 <-> obj%p0.tgt#0: NoAlias
+// CHECK-DAG: obj%p0#0 <-> obj%p1.tgt#0: NoAlias
+// CHECK-DAG: obj%p0.tgt#0 <-> obj%p1#0: NoAlias
+// CHECK-DAG: obj%p1#0 <-> obj%p1.tgt#0: NoAlias
+// CHECK-DAG: obj%p0.fir#0 <-> obj%p0.tgt.fir#0: NoAlias
+// CHECK-DAG: obj%p0.fir#0 <-> obj%p1.tgt.fir#0: NoAlias
+// CHECK-DAG: obj%p0.tgt.fir#0 <-> obj%p1.fir#0: NoAlias
+// CHECK-DAG: obj%p1.fir#0 <-> obj%p1.tgt.fir#0: NoAlias
+
+// For some cases, AliasAnalysis analyzes hlfir.designate like fir.box_addr, so
+// make sure it doesn't mistakenly see the address of obj%arr(1) as an address
+// that was loaded from a pointer and that could alias something.  However,
+// t_obj%arr is a target.
+// TODO: Thus, we expect the first case (and corresponding .fir case) below to
+// be NoAlias.  However, the addresses obj%p0.tgt and obj%arr(1) are analyzed as
+// MayAlias because they have the same source and both are data.
+// CHECK-DAG: obj%p0.tgt#0 <-> obj%arr(1)#0: MayAlias
+// CHECK-DAG: obj%p0.tgt#0 <-> t_obj%arr(1)#0: MayAlias
+// CHECK-DAG: obj%p0.tgt.fir#0 <-> obj%arr(1).fir#0: MayAlias
+// CHECK-DAG: obj%p0.tgt.fir#0 <-> t_obj%arr(1).fir#0: MayAlias
+
+// Like a pointer, an allocatable contains an address, but an allocatable is not
+// a pointer and so cannot alias pointers.  However, t_obj%alloc is a target.
+// TODO: Thus, we expect the first case (and corresponding .fir case) below to
+// be NoAlias.  However, the addresses obj%p0.tgt and obj%alloc.tgt are analyzed
+// as MayAlias because they have the same source and both are data.
+// CHECK-DAG: obj%p0.tgt#0 <-> obj%alloc.tgt#0: MayAlias
+// CHECK-DAG: obj%p0.tgt#0 <-> t_obj%alloc.tgt#0: MayAlias
+// CHECK-DAG: obj%p0.tgt.fir#0 <-> obj%alloc.tgt.fir#0: MayAlias
+// CHECK-DAG: obj%p0.tgt.fir#0 <-> t_obj%alloc.tgt.fir#0: MayAlias
+
+// The address in an allocatable cannot alias the address of that allocatable.
+// CHECK-DAG: obj%alloc#0 <-> obj%alloc.tgt#0: NoAlias
+// CHECK-DAG: t_obj%alloc#0 <-> t_obj%alloc.tgt#0: NoAlias
+// CHECK-DAG: obj%alloc.fir#0 <-> obj%alloc.tgt.fir#0: NoAlias
+// CHECK-DAG: t_obj%alloc.fir#0 <-> t_obj%alloc.tgt.fir#0: NoAlias
+
+// The address of a composite aliases the address of any component but not the
+// address in a pointer or allocatable component.
+// TODO: Thus, we expect the obj%*.tgt cases below to be NoAlias.  However, the
+// addresses obj and obj%*.tgt are analyzed as MayAlias because they have the
+// same source and both are data.
+// CHECK-DAG: obj#0 <-> obj%p0#0: MayAlias
+// CHECK-DAG: obj#0 <-> obj%alloc#0: MayAlias
+// CHECK-DAG: obj#0 <-> obj%p0.tgt#0: MayAlias
+// CHECK-DAG: obj#0 <-> obj%alloc.tgt#0: MayAlias
+// CHECK-DAG: obj.fir#0 <-> obj%p0.fir#0: MayAlias
+// CHECK-DAG: obj.fir#0 <-> obj%alloc.fir#0: MayAlias
+// CHECK-DAG: obj.fir#0 <-> obj%p0.tgt.fir#0: MayAlias
+// CHECK-DAG: obj.fir#0 <-> obj%alloc.tgt.fir#0: MayAlias
+
+func.func @_QPtest() {
+  %0 = fir.alloca !fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}> {bindc_name = "obj", uniq_name = "_QFtestEobj"}
+  %1:2 = hlfir.declare %0 {test.ptr="obj", uniq_name = "_QFtestEobj"} : (!fir.ref<!fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>>) -> (!fir.ref<!fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>>, !fir.ref<!fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>>)
+  %2 = fir.alloca f32 {bindc_name = "t", fir.target, uniq_name = "_QFtestEt"}
+  %3:2 = hlfir.declare %2 {test.ptr="t", fortran_attrs = #fir.var_attrs<target>, uniq_name = "_QFtestEt"} : (!fir.ref<f32>) -> (!fir.ref<f32>, !fir.ref<f32>)
+  %4 = fir.alloca !fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}> {bindc_name = "t_obj", fir.target, uniq_name = "_QFtestEt_obj"}
+  %5:2 = hlfir.declare %4 {test.ptr="t_obj", fortran_attrs = #fir.var_attrs<target>, uniq_name = "_QFtestEt_obj"} : (!fir.ref<!fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>>) -> (!fir.ref<!fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>>, !fir.ref<!fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>>)
+  %6 = fir.alloca f32 {bindc_name = "v", uniq_name = "_QFtestEv"}
+  %7:2 = hlfir.declare %6 {test.ptr="v", uniq_name = "_QFtestEv"} : (!fir.ref<f32>) -> (!fir.ref<f32>, !fir.ref<f32>)
+  %8 = hlfir.designate %1#0{"p0"}   {test.ptr="obj%p0", fortran_attrs = #fir.var_attrs<pointer>} : (!fir.ref<!fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>>) -> !fir.ref<!fir.box<!fir.ptr<f32>>>
+  %9 = fir.load %8 : !fir.ref<!fir.box<!fir.ptr<f32>>>
+  %10 = fir.box_addr %9 {test.ptr="obj%p0.tgt"} : (!fir.box<!fir.ptr<f32>>) -> !fir.ptr<f32>
+  %11 = hlfir.designate %1#0{"p1"}   {test.ptr="obj%p1", fortran_attrs = #fir.var_attrs<pointer>} : (!fir.ref<!fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>>) -> !fir.ref<!fir.box<!fir.ptr<f32>>>
+  %12 = fir.load %11 : !fir.ref<!fir.box<!fir.ptr<f32>>>
+  %13 = fir.box_addr %12 {test.ptr="obj%p1.tgt"}: (!fir.box<!fir.ptr<f32>>) -> !fir.ptr<f32>
+  %c2 = arith.constant 2 : index
+  %14 = fir.shape %c2 : (index) -> !fir.shape<1>
+  %c1 = arith.constant 1 : index
+  %15 = hlfir.designate %1#0{"arr"} <%14> (%c1) {test.ptr="obj%arr(1)"} : (!fir.ref<!fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>>, !fir.shape<1>, index) -> !fir.ref<f32>
+  %16 = hlfir.designate %1#0{"alloc"}   {test.ptr="obj%alloc", fortran_attrs = #fir.var_attrs<allocatable>} : (!fir.ref<!fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>>) -> !fir.ref<!fir.box<!fir.heap<f32>>>
+  %17 = fir.load %16 : !fir.ref<!fir.box<!fir.heap<f32>>>
+  %18 = fir.box_addr %17 {test.ptr="obj%alloc.tgt"}: (!fir.box<!fir.heap<f32>>) -> !fir.heap<f32>
+  %c2_1 = arith.constant 2 : index
+  %19 = fir.shape %c2_1 : (index) -> !fir.shape<1>
+  %c1_2 = arith.constant 1 : index
+  %20 = hlfir.designate %5#0{"arr"} <%19> (%c1_2) {test.ptr="t_obj%arr(1)"} : (!fir.ref<!fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>>, !fir.shape<1>, index) -> !fir.ref<f32>
+  %21 = hlfir.designate %5#0{"alloc"}   {test.ptr="t_obj%alloc", fortran_attrs = #fir.var_attrs<allocatable>} : (!fir.ref<!fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>>) -> !fir.ref<!fir.box<!fir.heap<f32>>>
+  %22 = fir.load %21 : !fir.ref<!fir.box<!fir.heap<f32>>>
+  %23 = fir.box_addr %22 {test.ptr="t_obj%alloc.tgt"} : (!fir.box<!fir.heap<f32>>) -> !fir.heap<f32>
+  return
+}
+
+func.func @_QPtest.fir() {
+  %0 = fir.alloca !fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}> {bindc_name = "obj", uniq_name = "_QFtestEobj"}
+  %1 = fir.declare %0 {test.ptr="obj.fir", uniq_name = "_QFtestEobj"} : (!fir.ref<!fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>>) -> !fir.ref<!fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>>
+  %2 = fir.alloca f32 {bindc_name = "t", fir.target, uniq_name = "_QFtestEt"}
+  %3 = fir.declare %2 {test.ptr = "t.fir", fortran_attrs = #fir.var_attrs<target>, uniq_name = "_QFtestEt"} : (!fir.ref<f32>) -> !fir.ref<f32>
+  %4 = fir.alloca !fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}> {bindc_name = "t_obj", fir.target, uniq_name = "_QFtestEt_obj"}
+  %5 = fir.declare %4 {test.ptr="t_obj.fir", fortran_attrs = #fir.var_attrs<target>, uniq_name = "_QFtestEt_obj"} : (!fir.ref<!fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>>) -> !fir.ref<!fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>>
+  %6 = fir.alloca f32 {bindc_name = "v", uniq_name = "_QFtestEv"}
+  %7 = fir.declare %6 {test.ptr = "v.fir", uniq_name = "_QFtestEv"} : (!fir.ref<f32>) -> !fir.ref<f32>
+  %8 = fir.field_index p0, !fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>
+  %9 = fir.coordinate_of %1, %8 {test.ptr="obj%p0.fir"} : (!fir.ref<!fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>>, !fir.field) -> !fir.ref<!fir.box<!fir.ptr<f32>>>
+  %10 = fir.load %9 : !fir.ref<!fir.box<!fir.ptr<f32>>>
+  %11 = fir.box_addr %10 {test.ptr = "obj%p0.tgt.fir"} : (!fir.box<!fir.ptr<f32>>) -> !fir.ptr<f32>
+  %12 = fir.field_index p1, !fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>
+  %13 = fir.coordinate_of %1, %12 {test.ptr="obj%p1.fir"} : (!fir.ref<!fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>>, !fir.field) -> !fir.ref<!fir.box<!fir.ptr<f32>>>
+  %14 = fir.load %13 : !fir.ref<!fir.box<!fir.ptr<f32>>>
+  %15 = fir.box_addr %14 {test.ptr = "obj%p1.tgt.fir"} : (!fir.box<!fir.ptr<f32>>) -> !fir.ptr<f32>
+  %c2 = arith.constant 2 : index
+  %16 = fir.shape %c2 : (index) -> !fir.shape<1>
+  %c1 = arith.constant 1 : index
+  %17 = fir.field_index arr, !fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>
+  %18 = fir.coordinate_of %1, %17 : (!fir.ref<!fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>>, !fir.field) -> !fir.ref<!fir.array<2xf32>>
+  %19 = fir.array_coor %18(%16) %c1 {test.ptr="obj%arr(1).fir"} : (!fir.ref<!fir.array<2xf32>>, !fir.shape<1>, index) -> !fir.ref<f32>
+  %20 = fir.field_index alloc, !fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>
+  %21 = fir.coordinate_of %1, %20 {test.ptr="obj%alloc.fir"} : (!fir.ref<!fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>>, !fir.field) -> !fir.ref<!fir.box<!fir.heap<f32>>>
+  %22 = fir.load %21 : !fir.ref<!fir.box<!fir.heap<f32>>>
+  %23 = fir.box_addr %22 {test.ptr = "obj%alloc.tgt.fir"} : (!fir.box<!fir.heap<f32>>) -> !fir.heap<f32>
+  %c2_0 = arith.constant 2 : index
+  %24 = fir.shape %c2_0 : (index) -> !fir.shape<1>
+  %c1_1 = arith.constant 1 : index
+  %25 = fir.field_index arr, !fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>
+  %26 = fir.coordinate_of %5, %25 : (!fir.ref<!fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>>, !fir.field) -> !fir.ref<!fir.array<2xf32>>
+  %27 = fir.array_coor %26(%24) %c1_1 {test.ptr="t_obj%arr(1).fir"} : (!fir.ref<!fir.array<2xf32>>, !fir.shape<1>, index) -> !fir.ref<f32>
+  %28 = fir.field_index alloc, !fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>
+  %29 = fir.coordinate_of %5, %28 {test.ptr="t_obj%alloc.fir"} : (!fir.ref<!fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>>, !fir.field) -> !fir.ref<!fir.box<!fir.heap<f32>>>
+  %30 = fir.load %29 : !fir.ref<!fir.box<!fir.heap<f32>>>
+  %31 = fir.box_addr %30 {test.ptr = "t_obj%alloc.tgt.fir"} : (!fir.box<!fir.heap<f32>>) -> !fir.heap<f32>
+  return
+}
+
+// -----
+
+// Repeat above test except composites are dummy args instead of locals.
+
+// module m
+//   type :: ty
+//     real, pointer :: p0, p1
+//     real :: arr(2)
+//     real, allocatable :: alloc
+//     ! target attribute on components is not supported
+//   end type ty
+// end module m
+// subroutine test(obj, t_obj)
+//   use m
+//   type(ty) :: obj
+//   type(ty), target :: t_obj
+//   real, target :: t
+//   real :: v
+// end subroutine test
+
+// CHECK-LABEL: Testing : "_QPtest"
+
+// The address in a pointer can alias the address in another pointer or the
+// address of a target but not the address of other variables.
+// CHECK-DAG: obj%p0.tgt#0 <-> obj%p1.tgt#0: MayAlias
+// CHECK-DAG: t#0 <-> obj%p0.tgt#0: MayAlias
+// CHECK-DAG: t#0 <-> obj%p1.tgt#0: MayAlias
+// CHECK-DAG: v#0 <-> obj%p0.tgt#0: NoAlias
+// CHECK-DAG: v#0 <-> obj%p1.tgt#0: NoAlias
+// CHECK-DAG: obj%p0.tgt.fir#0 <-> obj%p1.tgt.fir#0: MayAlias
+// CHECK-DAG: t.fir#0 <-> obj%p0.tgt.fir#0: MayAlias
+// CHECK-DAG: t.fir#0 <-> obj%p1.tgt.fir#0: MayAlias
+// CHECK-DAG: v.fir#0 <-> obj%p0.tgt.fir#0: NoAlias
+// CHECK-DAG: v.fir#0 <-> obj%p1.tgt.fir#0: NoAlias
+
+// The address in a pointer cannot alias the address of a pointer.
+// CHECK-DAG: obj%p0#0 <-> obj%p0.tgt#0: NoAlias
+// CHECK-DAG: obj%p0#0 <-> obj%p1.tgt#0: NoAlias
+// CHECK-DAG: obj%p0.tgt#0 <-> obj%p1#0: NoAlias
+// CHECK-DAG: obj%p1#0 <-> obj%p1.tgt#0: NoAlias
+// CHECK-DAG: obj%p0.fir#0 <-> obj%p0.tgt.fir#0: NoAlias
+// CHECK-DAG: obj%p0.fir#0 <-> obj%p1.tgt.fir#0: NoAlias
+// CHECK-DAG: obj%p0.tgt.fir#0 <-> obj%p1.fir#0: NoAlias
+// CHECK-DAG: obj%p1.fir#0 <-> obj%p1.tgt.fir#0: NoAlias
+
+// For some cases, AliasAnalysis analyzes hlfir.designate like fir.box_addr, so
+// make sure it doesn't mistakenly see the address of obj%arr(1) as an address
+// that was loaded from a pointer and that could alias something.  However,
+// t_obj%arr is a target.
+// TODO: Thus, we expect the first case (and corresponding .fir case) below to
+// be NoAlias.  However, the addresses obj%p0.tgt and obj%arr(1) are analyzed as
+// MayAlias because they have the same source and both are data.
+// CHECK-DAG: obj%p0.tgt#0 <-> obj%arr(1)#0: MayAlias
+// CHECK-DAG: obj%p0.tgt#0 <-> t_obj%arr(1)#0: MayAlias
+// CHECK-DAG: obj%p0.tgt.fir#0 <-> obj%arr(1).fir#0: MayAlias
+// CHECK-DAG: obj%p0.tgt.fir#0 <-> t_obj%arr(1).fir#0: MayAlias
+
+// Like a pointer, an allocatable contains an address, but an allocatable is not
+// a pointer and so cannot alias pointers.  However, t_obj%alloc is a target.
+// TODO: Thus, we expect the first case (and corresponding .fir case) below to
+// be NoAlias.  However, the addresses obj%p0.tgt and obj%alloc.tgt are analyzed
+// as MayAlias because they have the same source and both are data.
+// CHECK-DAG: obj%p0.tgt#0 <-> obj%alloc.tgt#0: MayAlias
+// CHECK-DAG: obj%p0.tgt#0 <-> t_obj%alloc.tgt#0: MayAlias
+// CHECK-DAG: obj%p0.tgt.fir#0 <-> obj%alloc.tgt.fir#0: MayAlias
+// CHECK-DAG: obj%p0.tgt.fir#0 <-> t_obj%alloc.tgt.fir#0: MayAlias
+
+// The address in an allocatable cannot alias the address of that allocatable.
+// TODO: Thus, we expect all cases below to be NoAlias.  However, target dummy
+// args are currently indiscrimnately analyzed as MayAlias.
+// CHECK-DAG: obj%alloc#0 <-> obj%alloc.tgt#0: NoAlias
+// CHECK-DAG: t_obj%alloc#0 <-> t_obj%alloc.tgt#0: MayAlias
+// CHECK-DAG: obj%alloc.fir#0 <-> obj%alloc.tgt.fir#0: NoAlias
+// CHECK-DAG: t_obj%alloc.fir#0 <-> t_obj%alloc.tgt.fir#0: MayAlias
+
+// The address of a composite aliases the address of any component but not the
+// address in a pointer or allocatable component.
+// TODO: Thus, we expect the obj%*.tgt cases below to be NoAlias.  However, the
+// addresses obj and obj%*.tgt are analyzed as MayAlias because they have the
+// same source and both are data.
+// CHECK-DAG: obj#0 <-> obj%p0#0: MayAlias
+// CHECK-DAG: obj#0 <-> obj%alloc#0: MayAlias
+// CHECK-DAG: obj#0 <-> obj%p0.tgt#0: MayAlias
+// CHECK-DAG: obj#0 <-> obj%alloc.tgt#0: MayAlias
+// CHECK-DAG: obj.fir#0 <-> obj%p0.fir#0: MayAlias
+// CHECK-DAG: obj.fir#0 <-> obj%alloc.fir#0: MayAlias
+// CHECK-DAG: obj.fir#0 <-> obj%p0.tgt.fir#0: MayAlias
+// CHECK-DAG: obj.fir#0 <-> obj%alloc.tgt.fir#0: MayAlias
+
+func.func @_QPtest(%arg0: !fir.ref<!fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>> {fir.bindc_name = "obj"}, %arg1: !fir.ref<!fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>> {fir.bindc_name = "t_obj", fir.target}) {
+  %0 = fir.dummy_scope : !fir.dscope
+  %1:2 = hlfir.declare %arg0 dummy_scope %0 {test.ptr="obj", uniq_name = "_QFtestEobj"} : (!fir.ref<!fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>>, !fir.dscope) -> (!fir.ref<!fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>>, !fir.ref<!fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>>)
+  %2 = fir.alloca f32 {bindc_name = "t", fir.target, uniq_name = "_QFtestEt"}
+  %3:2 = hlfir.declare %2 {test.ptr="t", fortran_attrs = #fir.var_attrs<target>, uniq_name = "_QFtestEt"} : (!fir.ref<f32>) -> (!fir.ref<f32>, !fir.ref<f32>)
+  %4:2 = hlfir.declare %arg1 dummy_scope %0 {test.ptr="t_obj", fortran_attrs = #fir.var_attrs<target>, uniq_name = "_QFtestEt_obj"} : (!fir.ref<!fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>>, !fir.dscope) -> (!fir.ref<!fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>>, !fir.ref<!fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>>)
+  %5 = fir.alloca f32 {bindc_name = "v", uniq_name = "_QFtestEv"}
+  %6:2 = hlfir.declare %5 {test.ptr="v", uniq_name = "_QFtestEv"} : (!fir.ref<f32>) -> (!fir.ref<f32>, !fir.ref<f32>)
+  %7 = hlfir.designate %1#0{"p0"}   {test.ptr="obj%p0", fortran_attrs = #fir.var_attrs<pointer>} : (!fir.ref<!fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>>) -> !fir.ref<!fir.box<!fir.ptr<f32>>>
+  %8 = fir.load %7 : !fir.ref<!fir.box<!fir.ptr<f32>>>
+  %9 = fir.box_addr %8 {test.ptr="obj%p0.tgt"} : (!fir.box<!fir.ptr<f32>>) -> !fir.ptr<f32>
+  %10 = hlfir.designate %1#0{"p1"}   {test.ptr="obj%p1", fortran_attrs = #fir.var_attrs<pointer>} : (!fir.ref<!fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>>) -> !fir.ref<!fir.box<!fir.ptr<f32>>>
+  %11 = fir.load %10 : !fir.ref<!fir.box<!fir.ptr<f32>>>
+  %12 = fir.box_addr %11 {test.ptr="obj%p1.tgt"} : (!fir.box<!fir.ptr<f32>>) -> !fir.ptr<f32>
+  %c2 = arith.constant 2 : index
+  %13 = fir.shape %c2 : (index) -> !fir.shape<1>
+  %c1 = arith.constant 1 : index
+  %14 = hlfir.designate %1#0{"arr"} <%13> (%c1) {test.ptr="obj%arr(1)"} : (!fir.ref<!fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>>, !fir.shape<1>, index) -> !fir.ref<f32>
+  %15 = hlfir.designate %1#0{"alloc"}   {test.ptr="obj%alloc", fortran_attrs = #fir.var_attrs<allocatable>} : (!fir.ref<!fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>>) -> !fir.ref<!fir.box<!fir.heap<f32>>>
+  %16 = fir.load %15 : !fir.ref<!fir.box<!fir.heap<f32>>>
+  %17 = fir.box_addr %16 {test.ptr="obj%alloc.tgt"} : (!fir.box<!fir.heap<f32>>) -> !fir.heap<f32>
+  %c2_0 = arith.constant 2 : index
+  %18 = fir.shape %c2_0 : (index) -> !fir.shape<1>
+  %c1_1 = arith.constant 1 : index
+  %19 = hlfir.designate %4#0{"arr"} <%18> (%c1_1) {test.ptr="t_obj%arr(1)"} : (!fir.ref<!fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>>, !fir.shape<1>, index) -> !fir.ref<f32>
+  %20 = hlfir.designate %4#0{"alloc"}   {test.ptr="t_obj%alloc", fortran_attrs = #fir.var_attrs<allocatable>} : (!fir.ref<!fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>>) -> !fir.ref<!fir.box<!fir.heap<f32>>>
+  %21 = fir.load %20 : !fir.ref<!fir.box<!fir.heap<f32>>>
+  %22 = fir.box_addr %21 {test.ptr="t_obj%alloc.tgt"} : (!fir.box<!fir.heap<f32>>) -> !fir.heap<f32>
+  return
+}
+
+func.func @_QPtest.fir(%arg0: !fir.ref<!fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>> {fir.bindc_name = "obj"}, %arg1: !fir.ref<!fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>> {fir.bindc_name = "t_obj", fir.target}) {
+  %0 = fir.dummy_scope : !fir.dscope
+  %1 = fir.declare %arg0 dummy_scope %0 {test.ptr="obj.fir", uniq_name = "_QFtestEobj"} : (!fir.ref<!fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>>, !fir.dscope) -> !fir.ref<!fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>>
+  %2 = fir.alloca f32 {bindc_name = "t", fir.target, uniq_name = "_QFtestEt"}
+  %3 = fir.declare %2 {test.ptr = "t.fir", fortran_attrs = #fir.var_attrs<target>, uniq_name = "_QFtestEt"} : (!fir.ref<f32>) -> !fir.ref<f32>
+  %4 = fir.declare %arg1 dummy_scope %0 {test.ptr="t_obj.fir", fortran_attrs = #fir.var_attrs<target>, uniq_name = "_QFtestEt_obj"} : (!fir.ref<!fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>>, !fir.dscope) -> !fir.ref<!fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>>
+  %5 = fir.alloca f32 {bindc_name = "v", uniq_name = "_QFtestEv"}
+  %6 = fir.declare %5 {test.ptr = "v.fir", uniq_name = "_QFtestEv"} : (!fir.ref<f32>) -> !fir.ref<f32>
+  %7 = fir.field_index p0, !fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>
+  %8 = fir.coordinate_of %1, %7 {test.ptr="obj%p0.fir"} : (!fir.ref<!fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>>, !fir.field) -> !fir.ref<!fir.box<!fir.ptr<f32>>>
+  %9 = fir.load %8 : !fir.ref<!fir.box<!fir.ptr<f32>>>
+  %10 = fir.box_addr %9 {test.ptr = "obj%p0.tgt.fir"} : (!fir.box<!fir.ptr<f32>>) -> !fir.ptr<f32>
+  %11 = fir.field_index p1, !fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>
+  %12 = fir.coordinate_of %1, %11 {test.ptr="obj%p1.fir"} : (!fir.ref<!fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>>, !fir.field) -> !fir.ref<!fir.box<!fir.ptr<f32>>>
+  %13 = fir.load %12 : !fir.ref<!fir.box<!fir.ptr<f32>>>
+  %14 = fir.box_addr %13 {test.ptr = "obj%p1.tgt.fir"} : (!fir.box<!fir.ptr<f32>>) -> !fir.ptr<f32>
+  %c2 = arith.constant 2 : index
+  %15 = fir.shape %c2 : (index) -> !fir.shape<1>
+  %c1 = arith.constant 1 : index
+  %16 = fir.field_index arr, !fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>
+  %17 = fir.coordinate_of %1, %16 : (!fir.ref<!fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>>, !fir.field) -> !fir.ref<!fir.array<2xf32>>
+  %18 = fir.array_coor %17(%15) %c1 {test.ptr="obj%arr(1).fir"} : (!fir.ref<!fir.array<2xf32>>, !fir.shape<1>, index) -> !fir.ref<f32>
+  %19 = fir.field_index alloc, !fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>
+  %20 = fir.coordinate_of %1, %19 {test.ptr="obj%alloc.fir"} : (!fir.ref<!fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>>, !fir.field) -> !fir.ref<!fir.box<!fir.heap<f32>>>
+  %21 = fir.load %20 : !fir.ref<!fir.box<!fir.heap<f32>>>
+  %22 = fir.box_addr %21 {test.ptr = "obj%alloc.tgt.fir"} : (!fir.box<!fir.heap<f32>>) -> !fir.heap<f32>
+  %c2_0 = arith.constant 2 : index
+  %23 = fir.shape %c2_0 : (index) -> !fir.shape<1>
+  %c1_1 = arith.constant 1 : index
+  %24 = fir.field_index arr, !fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>
+  %25 = fir.coordinate_of %4, %24 : (!fir.ref<!fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>>, !fir.field) -> !fir.ref<!fir.array<2xf32>>
+  %26 = fir.array_coor %25(%23) %c1_1 {test.ptr="t_obj%arr(1).fir"} : (!fir.ref<!fir.array<2xf32>>, !fir.shape<1>, index) -> !fir.ref<f32>
+  %27 = fir.field_index alloc, !fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>
+  %28 = fir.coordinate_of %4, %27 {test.ptr="t_obj%alloc.fir"} : (!fir.ref<!fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>>, !fir.field) -> !fir.ref<!fir.box<!fir.heap<f32>>>
+  %29 = fir.load %28 : !fir.ref<!fir.box<!fir.heap<f32>>>
+  %30 = fir.box_addr %29 {test.ptr = "t_obj%alloc.tgt.fir"} : (!fir.box<!fir.heap<f32>>) -> !fir.heap<f32>
+  return
+}
+
+// -----
+
+// Repeat above test except composites are globals.
+
+// module m
+//   type :: ty
+//     real, pointer :: p0, p1
+//     real :: arr(2)
+//     real, allocatable :: alloc
+//     ! target attribute on components is not supported
+//   end type ty
+//   type(ty) :: obj
+//   type(ty), target :: t_obj
+// end module m
+// subroutine test()
+//   use m
+//   real, target :: t
+//   real :: v
+// end subroutine test
+
+// CHECK-LABEL: Testing : "_QPtest"
+
+// The address in a pointer can alias the address in another pointer or the
+// address of a target but not the address of other variables.
+// CHECK-DAG: obj%p0.tgt#0 <-> obj%p1.tgt#0: MayAlias
+// CHECK-DAG: t#0 <-> obj%p0.tgt#0: MayAlias
+// CHECK-DAG: t#0 <-> obj%p1.tgt#0: MayAlias
+// CHECK-DAG: v#0 <-> obj%p0.tgt#0: NoAlias
+// CHECK-DAG: v#0 <-> obj%p1.tgt#0: NoAlias
+// CHECK-DAG: obj%p0.tgt.fir#0 <-> obj%p1.tgt.fir#0: MayAlias
+// CHECK-DAG: t.fir#0 <-> obj%p0.tgt.fir#0: MayAlias
+// CHECK-DAG: t.fir#0 <-> obj%p1.tgt.fir#0: MayAlias
+// CHECK-DAG: v.fir#0 <-> obj%p0.tgt.fir#0: NoAlias
+// CHECK-DAG: v.fir#0 <-> obj%p1.tgt.fir#0: NoAlias
+
+// The address in a pointer cannot alias the address of a pointer.
+// CHECK-DAG: obj%p0#0 <-> obj%p0.tgt#0: NoAlias
+// CHECK-DAG: obj%p0#0 <-> obj%p1.tgt#0: NoAlias
+// CHECK-DAG: obj%p0.tgt#0 <-> obj%p1#0: NoAlias
+// CHECK-DAG: obj%p1#0 <-> obj%p1.tgt#0: NoAlias
+// CHECK-DAG: obj%p0.fir#0 <-> obj%p0.tgt.fir#0: NoAlias
+// CHECK-DAG: obj%p0.fir#0 <-> obj%p1.tgt.fir#0: NoAlias
+// CHECK-DAG: obj%p0.tgt.fir#0 <-> obj%p1.fir#0: NoAlias
+// CHECK-DAG: obj%p1.fir#0 <-> obj%p1.tgt.fir#0: NoAlias
+
+// For some cases, AliasAnalysis analyzes hlfir.designate like fir.box_addr, so
+// make sure it doesn't mistakenly see the address of obj%arr(1) as an address
+// that was loaded from a pointer and that could alias something.  However,
+// t_obj%arr is a target.
+// TODO: Thus, we expect the first case (and corresponding .fir case) below to
+// be NoAlias.  However, the addresses obj%p0.tgt and obj%arr(1) are analyzed as
+// MayAlias because they have the same source and both are data.
+// CHECK-DAG: obj%p0.tgt#0 <-> obj%arr(1)#0: MayAlias
+// CHECK-DAG: obj%p0.tgt#0 <-> t_obj%arr(1)#0: MayAlias
+// CHECK-DAG: obj%p0.tgt.fir#0 <-> obj%arr(1).fir#0: MayAlias
+// CHECK-DAG: obj%p0.tgt.fir#0 <-> t_obj%arr(1).fir#0: MayAlias
+
+// Like a pointer, an allocatable contains an address, but an allocatable is not
+// a pointer and so cannot alias pointers.  However, t_obj%alloc is a target.
+// TODO: Thus, we expect the first case (and corresponding .fir case) below to
+// be NoAlias.  However, the addresses obj%p0.tgt and obj%alloc.tgt are analyzed
+// as MayAlias because they have the same source and both are data.
+// CHECK-DAG: obj%p0.tgt#0 <-> obj%alloc.tgt#0: MayAlias
+// CHECK-DAG: obj%p0.tgt#0 <-> t_obj%alloc.tgt#0: MayAlias
+// CHECK-DAG: obj%p0.tgt.fir#0 <-> obj%alloc.tgt.fir#0: MayAlias
+// CHECK-DAG: obj%p0.tgt.fir#0 <-> t_obj%alloc.tgt.fir#0: MayAlias
+
+// The address in an allocatable cannot alias the address of that allocatable.
+// CHECK-DAG: obj%alloc#0 <-> obj%alloc.tgt#0: NoAlias
+// CHECK-DAG: t_obj%alloc#0 <-> t_obj%alloc.tgt#0: NoAlias
+// CHECK-DAG: obj%alloc.fir#0 <-> obj%alloc.tgt.fir#0: NoAlias
+// CHECK-DAG: t_obj%alloc.fir#0 <-> t_obj%alloc.tgt.fir#0: NoAlias
+
+// The address of a composite aliases the address of any component but not the
+// address in a pointer or allocatable component.
+// TODO: Thus, we expect the obj%*.tgt cases below to be NoAlias.  However, the
+// addresses obj and obj%*.tgt are analyzed as MayAlias because they have the
+// same source and both are data.
+// CHECK-DAG: obj#0 <-> obj%p0#0: MayAlias
+// CHECK-DAG: obj#0 <-> obj%alloc#0: MayAlias
+// CHECK-DAG: obj#0 <-> obj%p0.tgt#0: MayAlias
+// CHECK-DAG: obj#0 <-> obj%alloc.tgt#0: MayAlias
+// CHECK-DAG: obj.fir#0 <-> obj%p0.fir#0: MayAlias
+// CHECK-DAG: obj.fir#0 <-> obj%alloc.fir#0: MayAlias
+// CHECK-DAG: obj.fir#0 <-> obj%p0.tgt.fir#0: MayAlias
+// CHECK-DAG: obj.fir#0 <-> obj%alloc.tgt.fir#0: MayAlias
+
+func.func @_QPtest() {
+  %0 = fir.address_of(@_QMmEobj) : !fir.ref<!fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>>
+  %1:2 = hlfir.declare %0 {test.ptr="obj", uniq_name = "_QMmEobj"} : (!fir.ref<!fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>>) -> (!fir.ref<!fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>>, !fir.ref<!fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>>)
+  %2 = fir.alloca f32 {bindc_name = "t", fir.target, uniq_name = "_QFtestEt"}
+  %3:2 = hlfir.declare %2 {test.ptr="t", fortran_attrs = #fir.var_attrs<target>, uniq_name = "_QFtestEt"} : (!fir.ref<f32>) -> (!fir.ref<f32>, !fir.ref<f32>)
+  %4 = fir.address_of(@_QMmEt_obj) : !fir.ref<!fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>>
+  %5:2 = hlfir.declare %4 {test.ptr="t_obj", fortran_attrs = #fir.var_attrs<target>, uniq_name = "_QMmEt_obj"} : (!fir.ref<!fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>>) -> (!fir.ref<!fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>>, !fir.ref<!fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>>)
+  %6 = fir.alloca f32 {bindc_name = "v", uniq_name = "_QFtestEv"}
+  %7:2 = hlfir.declare %6 {test.ptr="v", uniq_name = "_QFtestEv"} : (!fir.ref<f32>) -> (!fir.ref<f32>, !fir.ref<f32>)
+  %8 = hlfir.designate %1#0{"p0"}   {test.ptr="obj%p0", fortran_attrs = #fir.var_attrs<pointer>} : (!fir.ref<!fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>>) -> !fir.ref<!fir.box<!fir.ptr<f32>>>
+  %9 = fir.load %8 : !fir.ref<!fir.box<!fir.ptr<f32>>>
+  %10 = fir.box_addr %9 {test.ptr="obj%p0.tgt"} : (!fir.box<!fir.ptr<f32>>) -> !fir.ptr<f32>
+  %12 = hlfir.designate %1#0{"p1"}   {test.ptr="obj%p1", fortran_attrs = #fir.var_attrs<pointer>} : (!fir.ref<!fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>>) -> !fir.ref<!fir.box<!fir.ptr<f32>>>
+  %13 = fir.load %12 : !fir.ref<!fir.box<!fir.ptr<f32>>>
+  %14 = fir.box_addr %13 {test.ptr="obj%p1.tgt"} : (!fir.box<!fir.ptr<f32>>) -> !fir.ptr<f32>
+  %c2 = arith.constant 2 : index
+  %16 = fir.shape %c2 : (index) -> !fir.shape<1>
+  %c1 = arith.constant 1 : index
+  %17 = hlfir.designate %1#0{"arr"} <%16> (%c1) {test.ptr="obj%arr(1)"} : (!fir.ref<!fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>>, !fir.shape<1>, index) -> !fir.ref<f32>
+  %19 = hlfir.designate %1#0{"alloc"}   {test.ptr="obj%alloc", fortran_attrs = #fir.var_attrs<allocatable>} : (!fir.ref<!fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>>) -> !fir.ref<!fir.box<!fir.heap<f32>>>
+  %20 = fir.load %19 : !fir.ref<!fir.box<!fir.heap<f32>>>
+  %21 = fir.box_addr %20 {test.ptr="obj%alloc.tgt"} : (!fir.box<!fir.heap<f32>>) -> !fir.heap<f32>
+  %c2_0 = arith.constant 2 : index
+  %23 = fir.shape %c2_0 : (index) -> !fir.shape<1>
+  %c1_1 = arith.constant 1 : index
+  %24 = hlfir.designate %5#0{"arr"} <%23> (%c1_1) {test.ptr="t_obj%arr(1)"} : (!fir.ref<!fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>>, !fir.shape<1>, index) -> !fir.ref<f32>
+  %26 = hlfir.designate %5#0{"alloc"}   {test.ptr="t_obj%alloc", fortran_attrs = #fir.var_attrs<allocatable>} : (!fir.ref<!fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>>) -> !fir.ref<!fir.box<!fir.heap<f32>>>
+  %27 = fir.load %26 : !fir.ref<!fir.box<!fir.heap<f32>>>
+  %28 = fir.box_addr %27 {test.ptr="t_obj%alloc.tgt"} : (!fir.box<!fir.heap<f32>>) -> !fir.heap<f32>
+  return
+}
+
+func.func @_QPtest.fir() {
+  %0 = fir.address_of(@_QMmEobj) : !fir.ref<!fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>>
+  %1 = fir.declare %0 {test.ptr="obj.fir", uniq_name = "_QMmEobj"} : (!fir.ref<!fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>>) -> !fir.ref<!fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>>
+  %2 = fir.alloca f32 {bindc_name = "t", fir.target, uniq_name = "_QFtestEt"}
+  %3 = fir.declare %2 {test.ptr = "t.fir", fortran_attrs = #fir.var_attrs<target>, uniq_name = "_QFtestEt"} : (!fir.ref<f32>) -> !fir.ref<f32>
+  %4 = fir.address_of(@_QMmEt_obj) : !fir.ref<!fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>>
+  %5 = fir.declare %4 {test.ptr="t_obj.fir", fortran_attrs = #fir.var_attrs<target>, uniq_name = "_QMmEt_obj"} : (!fir.ref<!fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>>) -> !fir.ref<!fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>>
+  %6 = fir.alloca f32 {bindc_name = "v", uniq_name = "_QFtestEv"}
+  %7 = fir.declare %6 {test.ptr = "v.fir", uniq_name = "_QFtestEv"} : (!fir.ref<f32>) -> !fir.ref<f32>
+  %8 = fir.field_index p0, !fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>
+  %9 = fir.coordinate_of %1, %8 {test.ptr="obj%p0.fir"} : (!fir.ref<!fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>>, !fir.field) -> !fir.ref<!fir.box<!fir.ptr<f32>>>
+  %10 = fir.load %9 : !fir.ref<!fir.box<!fir.ptr<f32>>>
+  %11 = fir.box_addr %10 {test.ptr = "obj%p0.tgt.fir"} : (!fir.box<!fir.ptr<f32>>) -> !fir.ptr<f32>
+  %12 = fir.field_index p1, !fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>
+  %13 = fir.coordinate_of %1, %12 {test.ptr="obj%p1.fir"} : (!fir.ref<!fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>>, !fir.field) -> !fir.ref<!fir.box<!fir.ptr<f32>>>
+  %14 = fir.load %13 : !fir.ref<!fir.box<!fir.ptr<f32>>>
+  %15 = fir.box_addr %14 {test.ptr = "obj%p1.tgt.fir"} : (!fir.box<!fir.ptr<f32>>) -> !fir.ptr<f32>
+  %c2 = arith.constant 2 : index
+  %16 = fir.shape %c2 : (index) -> !fir.shape<1>
+  %c1 = arith.constant 1 : index
+  %17 = fir.field_index arr, !fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>
+  %18 = fir.coordinate_of %1, %17 : (!fir.ref<!fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>>, !fir.field) -> !fir.ref<!fir.array<2xf32>>
+  %19 = fir.array_coor %18(%16) %c1 {test.ptr="obj%arr(1).fir"} : (!fir.ref<!fir.array<2xf32>>, !fir.shape<1>, index) -> !fir.ref<f32>
+  %20 = fir.field_index alloc, !fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>
+  %21 = fir.coordinate_of %1, %20 {test.ptr="obj%alloc.fir"} : (!fir.ref<!fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>>, !fir.field) -> !fir.ref<!fir.box<!fir.heap<f32>>>
+  %22 = fir.load %21 : !fir.ref<!fir.box<!fir.heap<f32>>>
+  %23 = fir.box_addr %22 {test.ptr = "obj%alloc.tgt.fir"} : (!fir.box<!fir.heap<f32>>) -> !fir.heap<f32>
+  %c2_0 = arith.constant 2 : index
+  %24 = fir.shape %c2_0 : (index) -> !fir.shape<1>
+  %c1_1 = arith.constant 1 : index
+  %25 = fir.field_index arr, !fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>
+  %26 = fir.coordinate_of %5, %25 : (!fir.ref<!fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>>, !fir.field) -> !fir.ref<!fir.array<2xf32>>
+  %27 = fir.array_coor %26(%24) %c1_1 {test.ptr="t_obj%arr(1).fir"} : (!fir.ref<!fir.array<2xf32>>, !fir.shape<1>, index) -> !fir.ref<f32>
+  %28 = fir.field_index alloc, !fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>
+  %29 = fir.coordinate_of %5, %28 {test.ptr="t_obj%alloc.fir"} : (!fir.ref<!fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>>, !fir.field) -> !fir.ref<!fir.box<!fir.heap<f32>>>
+  %30 = fir.load %29 : !fir.ref<!fir.box<!fir.heap<f32>>>
+  %31 = fir.box_addr %30 {test.ptr = "t_obj%alloc.tgt.fir"} : (!fir.box<!fir.heap<f32>>) -> !fir.heap<f32>
+  return
+}

>From f3719ce85553b88815438d624343fb3609416314 Mon Sep 17 00:00:00 2001
From: "Joel E. Denny" <jdenny.ornl at gmail.com>
Date: Mon, 17 Feb 2025 15:50:16 -0500
Subject: [PATCH 2/2] Test multiple loads from the same alloca

---
 .../AliasAnalysis/load-ptr-designate.fir      | 27 +++++++++++++++++++
 1 file changed, 27 insertions(+)

diff --git a/flang/test/Analysis/AliasAnalysis/load-ptr-designate.fir b/flang/test/Analysis/AliasAnalysis/load-ptr-designate.fir
index 192de7f96f928..de81841d9249d 100644
--- a/flang/test/Analysis/AliasAnalysis/load-ptr-designate.fir
+++ b/flang/test/Analysis/AliasAnalysis/load-ptr-designate.fir
@@ -93,6 +93,11 @@
 // CHECK-DAG: obj.fir#0 <-> obj%p0.tgt.fir#0: MayAlias
 // CHECK-DAG: obj.fir#0 <-> obj%alloc.tgt.fir#0: MayAlias
 
+// The addresses obtained via multiple load instructions from the same
+// allocatable can alias.
+// CHECK-DAG: obj%alloc.tgt#0 <-> obj%alloc.tgt2#0: MayAlias
+// CHECK-DAG: obj%alloc.tgt.fir#0 <-> obj%alloc.tgt2.fir#0: MayAlias
+
 func.func @_QPtest() {
   %0 = fir.alloca !fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}> {bindc_name = "obj", uniq_name = "_QFtestEobj"}
   %1:2 = hlfir.declare %0 {test.ptr="obj", uniq_name = "_QFtestEobj"} : (!fir.ref<!fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>>) -> (!fir.ref<!fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>>, !fir.ref<!fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>>)
@@ -114,7 +119,9 @@ func.func @_QPtest() {
   %15 = hlfir.designate %1#0{"arr"} <%14> (%c1) {test.ptr="obj%arr(1)"} : (!fir.ref<!fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>>, !fir.shape<1>, index) -> !fir.ref<f32>
   %16 = hlfir.designate %1#0{"alloc"}   {test.ptr="obj%alloc", fortran_attrs = #fir.var_attrs<allocatable>} : (!fir.ref<!fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>>) -> !fir.ref<!fir.box<!fir.heap<f32>>>
   %17 = fir.load %16 : !fir.ref<!fir.box<!fir.heap<f32>>>
+  %repeat17 = fir.load %16 : !fir.ref<!fir.box<!fir.heap<f32>>>
   %18 = fir.box_addr %17 {test.ptr="obj%alloc.tgt"}: (!fir.box<!fir.heap<f32>>) -> !fir.heap<f32>
+  %repeat18 = fir.box_addr %repeat17 {test.ptr="obj%alloc.tgt2"}: (!fir.box<!fir.heap<f32>>) -> !fir.heap<f32>
   %c2_1 = arith.constant 2 : index
   %19 = fir.shape %c2_1 : (index) -> !fir.shape<1>
   %c1_2 = arith.constant 1 : index
@@ -151,7 +158,9 @@ func.func @_QPtest.fir() {
   %20 = fir.field_index alloc, !fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>
   %21 = fir.coordinate_of %1, %20 {test.ptr="obj%alloc.fir"} : (!fir.ref<!fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>>, !fir.field) -> !fir.ref<!fir.box<!fir.heap<f32>>>
   %22 = fir.load %21 : !fir.ref<!fir.box<!fir.heap<f32>>>
+  %repeat22 = fir.load %21 : !fir.ref<!fir.box<!fir.heap<f32>>>
   %23 = fir.box_addr %22 {test.ptr = "obj%alloc.tgt.fir"} : (!fir.box<!fir.heap<f32>>) -> !fir.heap<f32>
+  %repeat23 = fir.box_addr %repeat22 {test.ptr = "obj%alloc.tgt2.fir"} : (!fir.box<!fir.heap<f32>>) -> !fir.heap<f32>
   %c2_0 = arith.constant 2 : index
   %24 = fir.shape %c2_0 : (index) -> !fir.shape<1>
   %c1_1 = arith.constant 1 : index
@@ -254,6 +263,11 @@ func.func @_QPtest.fir() {
 // CHECK-DAG: obj.fir#0 <-> obj%p0.tgt.fir#0: MayAlias
 // CHECK-DAG: obj.fir#0 <-> obj%alloc.tgt.fir#0: MayAlias
 
+// The addresses obtained via multiple load instructions from the same
+// allocatable can alias.
+// CHECK-DAG: obj%alloc.tgt#0 <-> obj%alloc.tgt2#0: MayAlias
+// CHECK-DAG: obj%alloc.tgt.fir#0 <-> obj%alloc.tgt2.fir#0: MayAlias
+
 func.func @_QPtest(%arg0: !fir.ref<!fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>> {fir.bindc_name = "obj"}, %arg1: !fir.ref<!fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>> {fir.bindc_name = "t_obj", fir.target}) {
   %0 = fir.dummy_scope : !fir.dscope
   %1:2 = hlfir.declare %arg0 dummy_scope %0 {test.ptr="obj", uniq_name = "_QFtestEobj"} : (!fir.ref<!fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>>, !fir.dscope) -> (!fir.ref<!fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>>, !fir.ref<!fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>>)
@@ -274,7 +288,9 @@ func.func @_QPtest(%arg0: !fir.ref<!fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,
   %14 = hlfir.designate %1#0{"arr"} <%13> (%c1) {test.ptr="obj%arr(1)"} : (!fir.ref<!fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>>, !fir.shape<1>, index) -> !fir.ref<f32>
   %15 = hlfir.designate %1#0{"alloc"}   {test.ptr="obj%alloc", fortran_attrs = #fir.var_attrs<allocatable>} : (!fir.ref<!fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>>) -> !fir.ref<!fir.box<!fir.heap<f32>>>
   %16 = fir.load %15 : !fir.ref<!fir.box<!fir.heap<f32>>>
+  %repeat16 = fir.load %15 : !fir.ref<!fir.box<!fir.heap<f32>>>
   %17 = fir.box_addr %16 {test.ptr="obj%alloc.tgt"} : (!fir.box<!fir.heap<f32>>) -> !fir.heap<f32>
+  %repeat17 = fir.box_addr %repeat16 {test.ptr="obj%alloc.tgt2"} : (!fir.box<!fir.heap<f32>>) -> !fir.heap<f32>
   %c2_0 = arith.constant 2 : index
   %18 = fir.shape %c2_0 : (index) -> !fir.shape<1>
   %c1_1 = arith.constant 1 : index
@@ -310,7 +326,9 @@ func.func @_QPtest.fir(%arg0: !fir.ref<!fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f3
   %19 = fir.field_index alloc, !fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>
   %20 = fir.coordinate_of %1, %19 {test.ptr="obj%alloc.fir"} : (!fir.ref<!fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>>, !fir.field) -> !fir.ref<!fir.box<!fir.heap<f32>>>
   %21 = fir.load %20 : !fir.ref<!fir.box<!fir.heap<f32>>>
+  %repeat21 = fir.load %20 : !fir.ref<!fir.box<!fir.heap<f32>>>
   %22 = fir.box_addr %21 {test.ptr = "obj%alloc.tgt.fir"} : (!fir.box<!fir.heap<f32>>) -> !fir.heap<f32>
+  %repeat22 = fir.box_addr %repeat21 {test.ptr = "obj%alloc.tgt2.fir"} : (!fir.box<!fir.heap<f32>>) -> !fir.heap<f32>
   %c2_0 = arith.constant 2 : index
   %23 = fir.shape %c2_0 : (index) -> !fir.shape<1>
   %c1_1 = arith.constant 1 : index
@@ -411,6 +429,11 @@ func.func @_QPtest.fir(%arg0: !fir.ref<!fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f3
 // CHECK-DAG: obj.fir#0 <-> obj%p0.tgt.fir#0: MayAlias
 // CHECK-DAG: obj.fir#0 <-> obj%alloc.tgt.fir#0: MayAlias
 
+// The addresses obtained via multiple load instructions from the same
+// allocatable can alias.
+// CHECK-DAG: obj%alloc.tgt#0 <-> obj%alloc.tgt2#0: MayAlias
+// CHECK-DAG: obj%alloc.tgt.fir#0 <-> obj%alloc.tgt2.fir#0: MayAlias
+
 func.func @_QPtest() {
   %0 = fir.address_of(@_QMmEobj) : !fir.ref<!fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>>
   %1:2 = hlfir.declare %0 {test.ptr="obj", uniq_name = "_QMmEobj"} : (!fir.ref<!fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>>) -> (!fir.ref<!fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>>, !fir.ref<!fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>>)
@@ -432,7 +455,9 @@ func.func @_QPtest() {
   %17 = hlfir.designate %1#0{"arr"} <%16> (%c1) {test.ptr="obj%arr(1)"} : (!fir.ref<!fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>>, !fir.shape<1>, index) -> !fir.ref<f32>
   %19 = hlfir.designate %1#0{"alloc"}   {test.ptr="obj%alloc", fortran_attrs = #fir.var_attrs<allocatable>} : (!fir.ref<!fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>>) -> !fir.ref<!fir.box<!fir.heap<f32>>>
   %20 = fir.load %19 : !fir.ref<!fir.box<!fir.heap<f32>>>
+  %repeat20 = fir.load %19 : !fir.ref<!fir.box<!fir.heap<f32>>>
   %21 = fir.box_addr %20 {test.ptr="obj%alloc.tgt"} : (!fir.box<!fir.heap<f32>>) -> !fir.heap<f32>
+  %repeat21 = fir.box_addr %repeat20 {test.ptr="obj%alloc.tgt2"} : (!fir.box<!fir.heap<f32>>) -> !fir.heap<f32>
   %c2_0 = arith.constant 2 : index
   %23 = fir.shape %c2_0 : (index) -> !fir.shape<1>
   %c1_1 = arith.constant 1 : index
@@ -469,7 +494,9 @@ func.func @_QPtest.fir() {
   %20 = fir.field_index alloc, !fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>
   %21 = fir.coordinate_of %1, %20 {test.ptr="obj%alloc.fir"} : (!fir.ref<!fir.type<_QMmTty{p0:!fir.box<!fir.ptr<f32>>,p1:!fir.box<!fir.ptr<f32>>,arr:!fir.array<2xf32>,alloc:!fir.box<!fir.heap<f32>>}>>, !fir.field) -> !fir.ref<!fir.box<!fir.heap<f32>>>
   %22 = fir.load %21 : !fir.ref<!fir.box<!fir.heap<f32>>>
+  %repeat22 = fir.load %21 : !fir.ref<!fir.box<!fir.heap<f32>>>
   %23 = fir.box_addr %22 {test.ptr = "obj%alloc.tgt.fir"} : (!fir.box<!fir.heap<f32>>) -> !fir.heap<f32>
+  %repeat23 = fir.box_addr %repeat22 {test.ptr = "obj%alloc.tgt2.fir"} : (!fir.box<!fir.heap<f32>>) -> !fir.heap<f32>
   %c2_0 = arith.constant 2 : index
   %24 = fir.shape %c2_0 : (index) -> !fir.shape<1>
   %c1_1 = arith.constant 1 : index



More information about the flang-commits mailing list