[flang-commits] [flang] [flang] AliasAnalysis: Handle fir.load on fir.alloca (PR #117785)

Joel E. Denny via flang-commits flang-commits at lists.llvm.org
Fri Dec 27 10:17:29 PST 2024


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

>From d32ff8617580d043218eee082799fb674cb74ef6 Mon Sep 17 00:00:00 2001
From: "Joel E. Denny" <jdenny.ornl at gmail.com>
Date: Tue, 26 Nov 2024 15:31:10 -0500
Subject: [PATCH 1/3] [flang] AliasAnalysis: Handle fir.load on fir.alloca

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

```
subroutine test()
  real, pointer :: p
  real, target :: t
  real :: v
  p => t
  v = p
end subroutine test
```
---
 .../lib/Optimizer/Analysis/AliasAnalysis.cpp  |  63 ++-
 .../AliasAnalysis/alias-analysis-2.fir        |  13 +-
 .../AliasAnalysis/load-ptr-alloca.fir         | 412 ++++++++++++++++++
 3 files changed, 465 insertions(+), 23 deletions(-)
 create mode 100644 flang/test/Analysis/AliasAnalysis/load-ptr-alloca.fir

diff --git a/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp b/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp
index 2b24791d6c7c52..284b3dadbcef96 100644
--- a/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp
+++ b/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp
@@ -31,21 +31,6 @@ using namespace mlir;
 // AliasAnalysis: alias
 //===----------------------------------------------------------------------===//
 
-/// Temporary function to skip through all the no op operations
-/// TODO: Generalize support of fir.load
-static mlir::Value getOriginalDef(mlir::Value v) {
-  mlir::Operation *defOp;
-  bool breakFromLoop = false;
-  while (!breakFromLoop && (defOp = v.getDefiningOp())) {
-    llvm::TypeSwitch<Operation *>(defOp)
-        .Case<fir::ConvertOp>([&](fir::ConvertOp op) { v = op.getValue(); })
-        .Case<fir::DeclareOp, hlfir::DeclareOp>(
-            [&](auto op) { v = op.getMemref(); })
-        .Default([&](auto op) { breakFromLoop = true; });
-  }
-  return v;
-}
-
 namespace fir {
 
 void AliasAnalysis::Source::print(llvm::raw_ostream &os) const {
@@ -497,6 +482,29 @@ static Value getPrivateArg(omp::BlockArgOpenMPOpInterface &argIface,
   return privateArg;
 }
 
+/// Temporary function to skip through all the no op operations
+/// TODO: Generalize support of fir.load
+static mlir::Value
+getOriginalDef(mlir::Value v,
+               fir::AliasAnalysis::Source::Attributes &attributes,
+               bool &isCapturedInInternalProcedure) {
+  mlir::Operation *defOp;
+  bool breakFromLoop = false;
+  while (!breakFromLoop && (defOp = v.getDefiningOp())) {
+    llvm::TypeSwitch<Operation *>(defOp)
+        .Case<fir::ConvertOp>([&](fir::ConvertOp op) { v = op.getValue(); })
+        .Case<fir::DeclareOp, hlfir::DeclareOp>([&](auto op) {
+          v = op.getMemref();
+          auto varIf = llvm::cast<fir::FortranVariableOpInterface>(defOp);
+          attributes |= getAttrsFromVariable(varIf);
+          isCapturedInInternalProcedure |=
+              varIf.isCapturedInInternalProcedure();
+        })
+        .Default([&](auto op) { breakFromLoop = true; });
+  }
+  return v;
+}
+
 AliasAnalysis::Source AliasAnalysis::getSource(mlir::Value v,
                                                bool getLastInstantiationPoint) {
   auto *defOp = v.getDefiningOp();
@@ -509,6 +517,17 @@ AliasAnalysis::Source AliasAnalysis::getSource(mlir::Value v,
   bool isBoxRef{fir::isa_ref_type(v.getType()) &&
                 mlir::isa<fir::BaseBoxType>(fir::unwrapRefType(v.getType()))};
   bool followingData = !isBoxRef;
+  // "fir.alloca !fir.ptr<...>" returns the address *of* a pointer and is thus
+  // non-data, and yet there's no box.  Don't treat it like data, or it will
+  // appear to alias like the address *in* a pointer.  TODO: That case occurs in
+  // our test suite (alias-analysis-2.fir), but does flang currently generate
+  // such code?  Perhaps we should update docs
+  // (AliasAnalysis::Source::SourceOrigin::isData) and debug output
+  // (AliasAnalysis::Source::print) for isData as the current wording implies
+  // !isData requires a box.
+  if (mlir::isa_and_nonnull<fir::AllocaOp, fir::AllocMemOp>(defOp) &&
+      isPointerReference(v.getType()))
+    followingData = false;
   mlir::SymbolRefAttr global;
   Source::Attributes attributes;
   mlir::Operation *instantiationPoint{nullptr};
@@ -522,6 +541,12 @@ AliasAnalysis::Source AliasAnalysis::getSource(mlir::Value v,
         .Case<fir::AllocaOp, fir::AllocMemOp>([&](auto op) {
           // Unique memory allocation.
           type = SourceKind::Allocate;
+          // If there's no DeclareOp, then we need to get the pointer attribute
+          // from the type.  TODO: That case occurs in our test suite
+          // (alias-analysis-2.fir), but does flang currently generate such
+          // code?
+          if (isPointerReference(ty))
+            attributes.set(Attribute::Pointer);
           breakFromLoop = true;
         })
         .Case<fir::ConvertOp>([&](auto op) {
@@ -554,10 +579,12 @@ AliasAnalysis::Source AliasAnalysis::getSource(mlir::Value v,
         .Case<fir::LoadOp>([&](auto op) {
           // If the load is from a leaf source, return the leaf. Do not track
           // through indirections otherwise.
-          // TODO: Add support to fir.alloca and fir.allocmem
-          auto def = getOriginalDef(op.getMemref());
+          // TODO: Add support to fir.allocmem.
+          auto def = getOriginalDef(op.getMemref(), attributes,
+                                    isCapturedInInternalProcedure);
           if (isDummyArgument(def) ||
-              def.template getDefiningOp<fir::AddrOfOp>()) {
+              def.template getDefiningOp<fir::AddrOfOp>() ||
+              def.template getDefiningOp<fir::AllocaOp>()) {
             v = def;
             defOp = v.getDefiningOp();
             return;
diff --git a/flang/test/Analysis/AliasAnalysis/alias-analysis-2.fir b/flang/test/Analysis/AliasAnalysis/alias-analysis-2.fir
index d03348efd2a68c..e2cdf8c8ddeb66 100644
--- a/flang/test/Analysis/AliasAnalysis/alias-analysis-2.fir
+++ b/flang/test/Analysis/AliasAnalysis/alias-analysis-2.fir
@@ -8,9 +8,11 @@
 // They cannot physically alias
 // CHECK-DAG: p1.addr#0 <-> p2.addr#0: NoAlias
 
-// p1.addr and p2.addr could both be wrapped inside boxes
-// CHECK-DAG: p1.addr#0 <-> boxp1.addr#0: MayAlias
-// CHECK-DAG: p2.addr#0 <-> boxp1.addr#0: MayAlias
+// p1.addr is the address returned by an alloca.  It does not have a target
+// attribute, and it is not the address retrieved from a pointer.  It cannot
+// alias anything.  Likewise for p2.addr.
+// CHECK-DAG: p1.addr#0 <-> boxp1.addr#0: NoAlias
+// CHECK-DAG: p2.addr#0 <-> boxp1.addr#0: NoAlias
 
 // TODO: To really see aliasing, we should be looking at a load of p1.addr
 // p1.addr is just a local address holding the address to the data 
@@ -27,10 +29,11 @@
 // CHECK-DAG: p2.addr#0 <-> func.region0#2: NoAlias
 
 // All arguments are either pointers or targets
-// A pointer in a box may alias with both
+// The address *in* a local pointer may alias the address of a target
+// argument, but it does not alias the address *of* a pointer argument.
 // CHECK-DAG: boxp1.addr#0 <-> func.region0#0: MayAlias
 // CHECK-DAG: boxp1.addr#0 <-> func.region0#1: MayAlias
-// CHECK-DAG: boxp1.addr#0 <-> func.region0#2: MayAlias
+// CHECK-DAG: boxp1.addr#0 <-> func.region0#2: NoAlias
 
 // A target dummy may alias with another target
 // CHECK-DAG: func.region0#0 <-> func.region0#1: MayAlias
diff --git a/flang/test/Analysis/AliasAnalysis/load-ptr-alloca.fir b/flang/test/Analysis/AliasAnalysis/load-ptr-alloca.fir
new file mode 100644
index 00000000000000..56c5313d397a51
--- /dev/null
+++ b/flang/test/Analysis/AliasAnalysis/load-ptr-alloca.fir
@@ -0,0 +1,412 @@
+// Check aliasing with the address *in* (not *of*) a local (fir.alloca) pointer
+// variable.
+//
+// Throughout this test, the ".fir" suffix on symbols indicates a version of the
+// MLIR after convert-hlfir-to-fir.  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
+
+// subroutine test(n)
+//   integer :: n
+//   real, pointer :: p0, p1
+//   real :: arr(n)
+//   real, target :: t_arr(n)
+//   real, allocatable :: alloc
+//   real, allocatable, target :: t_alloc
+//   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: p0.tgt#0 <-> p1.tgt#0: MayAlias
+// CHECK-DAG: t#0 <-> p0.tgt#0: MayAlias
+// CHECK-DAG: t#0 <-> p1.tgt#0: MayAlias
+// CHECK-DAG: v#0 <-> p0.tgt#0: NoAlias
+// CHECK-DAG: v#0 <-> p1.tgt#0: NoAlias
+// CHECK-DAG: p0.tgt.fir#0 <-> p1.tgt.fir#0: MayAlias
+// CHECK-DAG: t.fir#0 <-> p0.tgt.fir#0: MayAlias
+// CHECK-DAG: t.fir#0 <-> p1.tgt.fir#0: MayAlias
+// CHECK-DAG: v.fir#0 <-> p0.tgt.fir#0: NoAlias
+// CHECK-DAG: v.fir#0 <-> p1.tgt.fir#0: NoAlias
+
+// The address in a pointer cannot alias the address of a pointer.
+// CHECK-DAG: p0#0 <-> p0.tgt#0: NoAlias
+// CHECK-DAG: p0#0 <-> p1.tgt#0: NoAlias
+// CHECK-DAG: p1#0 <-> p0.tgt#0: NoAlias
+// CHECK-DAG: p1#0 <-> p1.tgt#0: NoAlias
+// CHECK-DAG: p0.fir#0 <-> p0.tgt.fir#0: NoAlias
+// CHECK-DAG: p0.fir#0 <-> p1.tgt.fir#0: NoAlias
+// CHECK-DAG: p1.fir#0 <-> p0.tgt.fir#0: NoAlias
+// CHECK-DAG: p1.fir#0 <-> 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 arr(1) as an address that
+// was loaded from a pointer and that could alias something.  However, t_arr is
+// a target.
+// CHECK-DAG: p0.tgt#0 <-> arr(1)#0: NoAlias
+// CHECK-DAG: p0.tgt#0 <-> t_arr(1)#0: MayAlias
+// CHECK-DAG: p0.tgt.fir#0 <-> arr(1).fir#0: NoAlias
+// CHECK-DAG: p0.tgt.fir#0 <-> t_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_alloc is a target.
+// CHECK-DAG: p0.tgt#0 <-> alloc.tgt#0: NoAlias
+// CHECK-DAG: p0.tgt#0 <-> t_alloc.tgt#0: MayAlias
+// CHECK-DAG: p0.tgt.fir#0 <-> alloc.tgt.fir#0: NoAlias
+// CHECK-DAG: p0.tgt.fir#0 <-> t_alloc.tgt.fir#0: MayAlias
+
+// The address in an allocatable cannot alias the address of that allocatable.
+// CHECK-DAG: alloc#0 <-> alloc.tgt#0: NoAlias
+// CHECK-DAG: alloc.fir#0 <-> alloc.tgt.fir#0: NoAlias
+
+func.func @_QPtest(%arg0: !fir.ref<i32> {fir.bindc_name = "n"}) {
+  %0 = fir.alloca !fir.box<!fir.heap<f32>> {bindc_name = "alloc", uniq_name = "_QFtestEalloc"}
+  %1:2 = hlfir.declare %0 {test.ptr="alloc", fortran_attrs = #fir.var_attrs<allocatable>, uniq_name = "_QFtestEalloc"} : (!fir.ref<!fir.box<!fir.heap<f32>>>) -> (!fir.ref<!fir.box<!fir.heap<f32>>>, !fir.ref<!fir.box<!fir.heap<f32>>>)
+  %2:2 = hlfir.declare %arg0 {uniq_name = "_QFtestEn"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+  %3 = fir.alloca !fir.box<!fir.ptr<f32>> {bindc_name = "p0", uniq_name = "_QFtestEp0"}
+  %4:2 = hlfir.declare %3 {test.ptr="p0", fortran_attrs = #fir.var_attrs<pointer>, uniq_name = "_QFtestEp0"} : (!fir.ref<!fir.box<!fir.ptr<f32>>>) -> (!fir.ref<!fir.box<!fir.ptr<f32>>>, !fir.ref<!fir.box<!fir.ptr<f32>>>)
+  %5 = fir.alloca !fir.box<!fir.ptr<f32>> {bindc_name = "p1", uniq_name = "_QFtestEp1"}
+  %6:2 = hlfir.declare %5 {test.ptr="p1", fortran_attrs = #fir.var_attrs<pointer>, uniq_name = "_QFtestEp1"} : (!fir.ref<!fir.box<!fir.ptr<f32>>>) -> (!fir.ref<!fir.box<!fir.ptr<f32>>>, !fir.ref<!fir.box<!fir.ptr<f32>>>)
+  %7 = fir.alloca f32 {bindc_name = "t", fir.target, uniq_name = "_QFtestEt"}
+  %8:2 = hlfir.declare %7 {test.ptr="t", fortran_attrs = #fir.var_attrs<target>, uniq_name = "_QFtestEt"} : (!fir.ref<f32>) -> (!fir.ref<f32>, !fir.ref<f32>)
+  %9 = fir.alloca !fir.box<!fir.heap<f32>> {bindc_name = "t_alloc", fir.target, uniq_name = "_QFtestEt_alloc"}
+  %10:2 = hlfir.declare %9 {fortran_attrs = #fir.var_attrs<allocatable, target>, uniq_name = "_QFtestEt_alloc"} : (!fir.ref<!fir.box<!fir.heap<f32>>>) -> (!fir.ref<!fir.box<!fir.heap<f32>>>, !fir.ref<!fir.box<!fir.heap<f32>>>)
+  %11 = fir.alloca f32 {bindc_name = "v", uniq_name = "_QFtestEv"}
+  %12:2 = hlfir.declare %11 {test.ptr="v", uniq_name = "_QFtestEv"} : (!fir.ref<f32>) -> (!fir.ref<f32>, !fir.ref<f32>)
+  %13 = fir.load %2#0 : !fir.ref<i32>
+  %14 = fir.convert %13 : (i32) -> i64
+  %15 = fir.convert %14 : (i64) -> index
+  %c0 = arith.constant 0 : index
+  %16 = arith.cmpi sgt, %15, %c0 : index
+  %17 = arith.select %16, %15, %c0 : index
+  %18 = fir.alloca !fir.array<?xf32>, %17 {bindc_name = "arr", uniq_name = "_QFtestEarr"}
+  %19 = fir.shape %17 : (index) -> !fir.shape<1>
+  %20:2 = hlfir.declare %18(%19) {uniq_name = "_QFtestEarr"} : (!fir.ref<!fir.array<?xf32>>, !fir.shape<1>) -> (!fir.box<!fir.array<?xf32>>, !fir.ref<!fir.array<?xf32>>)
+  %21 = fir.load %2#0 : !fir.ref<i32>
+  %22 = fir.convert %21 : (i32) -> i64
+  %23 = fir.convert %22 : (i64) -> index
+  %c0_0 = arith.constant 0 : index
+  %24 = arith.cmpi sgt, %23, %c0_0 : index
+  %25 = arith.select %24, %23, %c0_0 : index
+  %26 = fir.alloca !fir.array<?xf32>, %25 {bindc_name = "t_arr", fir.target, uniq_name = "_QFtestEt_arr"}
+  %27 = fir.shape %25 : (index) -> !fir.shape<1>
+  %28:2 = hlfir.declare %26(%27) {fortran_attrs = #fir.var_attrs<target>, uniq_name = "_QFtestEt_arr"} : (!fir.ref<!fir.array<?xf32>>, !fir.shape<1>) -> (!fir.box<!fir.array<?xf32>>, !fir.ref<!fir.array<?xf32>>)
+  %29 = fir.load %4#0 : !fir.ref<!fir.box<!fir.ptr<f32>>>
+  %30 = fir.box_addr %29 {test.ptr="p0.tgt"} : (!fir.box<!fir.ptr<f32>>) -> !fir.ptr<f32>
+  %31 = fir.load %6#0 : !fir.ref<!fir.box<!fir.ptr<f32>>>
+  %32 = fir.box_addr %31 {test.ptr="p1.tgt"} : (!fir.box<!fir.ptr<f32>>) -> !fir.ptr<f32>
+  %c1 = arith.constant 1 : index
+  %33 = hlfir.designate %20#0 (%c1) {test.ptr="arr(1)"} : (!fir.box<!fir.array<?xf32>>, index) -> !fir.ref<f32>
+  %c1_1 = arith.constant 1 : index
+  %34 = hlfir.designate %28#0 (%c1_1) {test.ptr="t_arr(1)"} : (!fir.box<!fir.array<?xf32>>, index) -> !fir.ref<f32>
+  %35 = fir.load %1#0 : !fir.ref<!fir.box<!fir.heap<f32>>>
+  %36 = fir.box_addr %35 {test.ptr="alloc.tgt"} : (!fir.box<!fir.heap<f32>>) -> !fir.heap<f32>
+  %37 = fir.load %10#0 : !fir.ref<!fir.box<!fir.heap<f32>>>
+  %38 = fir.box_addr %37 {test.ptr="t_alloc.tgt"} : (!fir.box<!fir.heap<f32>>) -> !fir.heap<f32>
+  return
+}
+
+func.func @_QPtest.fir(%arg0: !fir.ref<i32> {fir.bindc_name = "n"}) {
+  %0 = fir.alloca !fir.box<!fir.heap<f32>> {bindc_name = "alloc", uniq_name = "_QFtestEalloc"}
+  %1 = fir.declare %0 {test.ptr = "alloc.fir", fortran_attrs = #fir.var_attrs<allocatable>, uniq_name = "_QFtestEalloc"} : (!fir.ref<!fir.box<!fir.heap<f32>>>) -> !fir.ref<!fir.box<!fir.heap<f32>>>
+  %2 = fir.declare %arg0 {uniq_name = "_QFtestEn"} : (!fir.ref<i32>) -> !fir.ref<i32>
+  %3 = fir.alloca !fir.box<!fir.ptr<f32>> {bindc_name = "p0", uniq_name = "_QFtestEp0"}
+  %4 = fir.declare %3 {test.ptr = "p0.fir", fortran_attrs = #fir.var_attrs<pointer>, uniq_name = "_QFtestEp0"} : (!fir.ref<!fir.box<!fir.ptr<f32>>>) -> !fir.ref<!fir.box<!fir.ptr<f32>>>
+  %5 = fir.alloca !fir.box<!fir.ptr<f32>> {bindc_name = "p1", uniq_name = "_QFtestEp1"}
+  %6 = fir.declare %5 {test.ptr = "p1.fir", fortran_attrs = #fir.var_attrs<pointer>, uniq_name = "_QFtestEp1"} : (!fir.ref<!fir.box<!fir.ptr<f32>>>) -> !fir.ref<!fir.box<!fir.ptr<f32>>>
+  %7 = fir.alloca f32 {bindc_name = "t", fir.target, uniq_name = "_QFtestEt"}
+  %8 = fir.declare %7 {test.ptr = "t.fir", fortran_attrs = #fir.var_attrs<target>, uniq_name = "_QFtestEt"} : (!fir.ref<f32>) -> !fir.ref<f32>
+  %9 = fir.alloca !fir.box<!fir.heap<f32>> {bindc_name = "t_alloc", fir.target, uniq_name = "_QFtestEt_alloc"}
+  %10 = fir.declare %9 {fortran_attrs = #fir.var_attrs<allocatable, target>, uniq_name = "_QFtestEt_alloc"} : (!fir.ref<!fir.box<!fir.heap<f32>>>) -> !fir.ref<!fir.box<!fir.heap<f32>>>
+  %11 = fir.alloca f32 {bindc_name = "v", uniq_name = "_QFtestEv"}
+  %12 = fir.declare %11 {test.ptr = "v.fir", uniq_name = "_QFtestEv"} : (!fir.ref<f32>) -> !fir.ref<f32>
+  %13 = fir.load %2 : !fir.ref<i32>
+  %14 = fir.convert %13 : (i32) -> i64
+  %15 = fir.convert %14 : (i64) -> index
+  %c0 = arith.constant 0 : index
+  %16 = arith.cmpi sgt, %15, %c0 : index
+  %17 = arith.select %16, %15, %c0 : index
+  %18 = fir.alloca !fir.array<?xf32>, %17 {bindc_name = "arr", uniq_name = "_QFtestEarr"}
+  %19 = fir.shape %17 : (index) -> !fir.shape<1>
+  %20 = fir.declare %18(%19) {uniq_name = "_QFtestEarr"} : (!fir.ref<!fir.array<?xf32>>, !fir.shape<1>) -> !fir.ref<!fir.array<?xf32>>
+  %21 = fir.embox %20(%19) : (!fir.ref<!fir.array<?xf32>>, !fir.shape<1>) -> !fir.box<!fir.array<?xf32>>
+  %22 = fir.load %2 : !fir.ref<i32>
+  %23 = fir.convert %22 : (i32) -> i64
+  %24 = fir.convert %23 : (i64) -> index
+  %c0_0 = arith.constant 0 : index
+  %25 = arith.cmpi sgt, %24, %c0_0 : index
+  %26 = arith.select %25, %24, %c0_0 : index
+  %27 = fir.alloca !fir.array<?xf32>, %26 {bindc_name = "t_arr", fir.target, uniq_name = "_QFtestEt_arr"}
+  %28 = fir.shape %26 : (index) -> !fir.shape<1>
+  %29 = fir.declare %27(%28) {fortran_attrs = #fir.var_attrs<target>, uniq_name = "_QFtestEt_arr"} : (!fir.ref<!fir.array<?xf32>>, !fir.shape<1>) -> !fir.ref<!fir.array<?xf32>>
+  %30 = fir.embox %29(%28) : (!fir.ref<!fir.array<?xf32>>, !fir.shape<1>) -> !fir.box<!fir.array<?xf32>>
+  %31 = fir.load %4 : !fir.ref<!fir.box<!fir.ptr<f32>>>
+  %32 = fir.box_addr %31 {test.ptr = "p0.tgt.fir"} : (!fir.box<!fir.ptr<f32>>) -> !fir.ptr<f32>
+  %33 = fir.load %6 : !fir.ref<!fir.box<!fir.ptr<f32>>>
+  %34 = fir.box_addr %33 {test.ptr = "p1.tgt.fir"} : (!fir.box<!fir.ptr<f32>>) -> !fir.ptr<f32>
+  %c1 = arith.constant 1 : index
+  %35 = fir.array_coor %20(%19) %c1 {test.ptr="arr(1).fir"} : (!fir.ref<!fir.array<?xf32>>, !fir.shape<1>, index) -> !fir.ref<f32>
+  %c1_1 = arith.constant 1 : index
+  %36 = fir.array_coor %29(%28) %c1_1 {test.ptr="t_arr(1).fir"} : (!fir.ref<!fir.array<?xf32>>, !fir.shape<1>, index) -> !fir.ref<f32>
+  %37 = fir.load %1 : !fir.ref<!fir.box<!fir.heap<f32>>>
+  %38 = fir.box_addr %37 {test.ptr = "alloc.tgt.fir"} : (!fir.box<!fir.heap<f32>>) -> !fir.heap<f32>
+  %39 = fir.load %10 : !fir.ref<!fir.box<!fir.heap<f32>>>
+  %40 = fir.box_addr %39 {test.ptr = "t_alloc.tgt.fir"} : (!fir.box<!fir.heap<f32>>) -> !fir.heap<f32>
+  return
+}
+
+// -----
+
+// Repeat above test except compare the local pointer against dummy args instead
+// of other locals.
+
+// subroutine test(p1, arr, t_arr, alloc, t_alloc, t, v)
+//   real, pointer :: p1
+//   real :: arr(:)
+//   real, target :: t_arr(:)
+//   real, allocatable :: alloc
+//   real, allocatable, target :: t_alloc
+//   real, target :: t
+//   real :: v
+//   real, pointer :: p0
+// 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: p0.tgt#0 <-> p1.tgt#0: MayAlias
+// CHECK-DAG: t#0 <-> p0.tgt#0: MayAlias
+// CHECK-DAG: t#0 <-> p1.tgt#0: MayAlias
+// CHECK-DAG: v#0 <-> p0.tgt#0: NoAlias
+// CHECK-DAG: v#0 <-> p1.tgt#0: NoAlias
+// CHECK-DAG: p0.tgt.fir#0 <-> p1.tgt.fir#0: MayAlias
+// CHECK-DAG: t.fir#0 <-> p0.tgt.fir#0: MayAlias
+// CHECK-DAG: t.fir#0 <-> p1.tgt.fir#0: MayAlias
+// CHECK-DAG: v.fir#0 <-> p0.tgt.fir#0: NoAlias
+// CHECK-DAG: v.fir#0 <-> p1.tgt.fir#0: NoAlias
+
+// The address in a pointer cannot alias the address of a pointer.
+// CHECK-DAG: p0#0 <-> p0.tgt#0: NoAlias
+// CHECK-DAG: p0#0 <-> p1.tgt#0: NoAlias
+// CHECK-DAG: p1#0 <-> p0.tgt#0: NoAlias
+// CHECK-DAG: p1#0 <-> p1.tgt#0: NoAlias
+// CHECK-DAG: p0.fir#0 <-> p0.tgt.fir#0: NoAlias
+// CHECK-DAG: p0.fir#0 <-> p1.tgt.fir#0: NoAlias
+// CHECK-DAG: p1.fir#0 <-> p0.tgt.fir#0: NoAlias
+// CHECK-DAG: p1.fir#0 <-> 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 arr(1) as an address that
+// was loaded from a pointer and that could alias something.  However, t_arr is
+// a target.
+// CHECK-DAG: p0.tgt#0 <-> arr(1)#0: NoAlias
+// CHECK-DAG: p0.tgt#0 <-> t_arr(1)#0: MayAlias
+// CHECK-DAG: p0.tgt.fir#0 <-> arr(1).fir#0: NoAlias
+// CHECK-DAG: p0.tgt.fir#0 <-> t_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_alloc is a target.
+// CHECK-DAG: p0.tgt#0 <-> alloc.tgt#0: NoAlias
+// CHECK-DAG: p0.tgt#0 <-> t_alloc.tgt#0: MayAlias
+// CHECK-DAG: p0.tgt.fir#0 <-> alloc.tgt.fir#0: NoAlias
+// CHECK-DAG: p0.tgt.fir#0 <-> t_alloc.tgt.fir#0: MayAlias
+
+// The address in an allocatable cannot alias the address of that allocatable.
+// CHECK-DAG: alloc#0 <-> alloc.tgt#0: NoAlias
+// CHECK-DAG: alloc.fir#0 <-> alloc.tgt.fir#0: NoAlias
+
+func.func @_QPtest(%arg0: !fir.ref<!fir.box<!fir.ptr<f32>>> {fir.bindc_name = "p1"}, %arg1: !fir.box<!fir.array<?xf32>> {fir.bindc_name = "arr"}, %arg2: !fir.box<!fir.array<?xf32>> {fir.bindc_name = "t_arr", fir.target}, %arg3: !fir.ref<!fir.box<!fir.heap<f32>>> {fir.bindc_name = "alloc"}, %arg4: !fir.ref<!fir.box<!fir.heap<f32>>> {fir.bindc_name = "t_alloc", fir.target}, %arg5: !fir.ref<f32> {fir.bindc_name = "t", fir.target}, %arg6: !fir.ref<f32> {fir.bindc_name = "v"}) {
+  %0 = fir.dummy_scope : !fir.dscope
+  %1:2 = hlfir.declare %arg3 dummy_scope %0 {test.ptr="alloc", fortran_attrs = #fir.var_attrs<allocatable>, uniq_name = "_QFtestEalloc"} : (!fir.ref<!fir.box<!fir.heap<f32>>>, !fir.dscope) -> (!fir.ref<!fir.box<!fir.heap<f32>>>, !fir.ref<!fir.box<!fir.heap<f32>>>)
+  %2:2 = hlfir.declare %arg1 dummy_scope %0 {uniq_name = "_QFtestEarr"} : (!fir.box<!fir.array<?xf32>>, !fir.dscope) -> (!fir.box<!fir.array<?xf32>>, !fir.box<!fir.array<?xf32>>)
+  %3 = fir.alloca !fir.box<!fir.ptr<f32>> {bindc_name = "p0", uniq_name = "_QFtestEp0"}
+  %4:2 = hlfir.declare %3 {test.ptr="p0", fortran_attrs = #fir.var_attrs<pointer>, uniq_name = "_QFtestEp0"} : (!fir.ref<!fir.box<!fir.ptr<f32>>>) -> (!fir.ref<!fir.box<!fir.ptr<f32>>>, !fir.ref<!fir.box<!fir.ptr<f32>>>)
+  %5:2 = hlfir.declare %arg0 dummy_scope %0 {test.ptr="p1", fortran_attrs = #fir.var_attrs<pointer>, uniq_name = "_QFtestEp1"} : (!fir.ref<!fir.box<!fir.ptr<f32>>>, !fir.dscope) -> (!fir.ref<!fir.box<!fir.ptr<f32>>>, !fir.ref<!fir.box<!fir.ptr<f32>>>)
+  %6:2 = hlfir.declare %arg5 dummy_scope %0 {test.ptr="t", fortran_attrs = #fir.var_attrs<target>, uniq_name = "_QFtestEt"} : (!fir.ref<f32>, !fir.dscope) -> (!fir.ref<f32>, !fir.ref<f32>)
+  %7:2 = hlfir.declare %arg4 dummy_scope %0 {fortran_attrs = #fir.var_attrs<allocatable, target>, uniq_name = "_QFtestEt_alloc"} : (!fir.ref<!fir.box<!fir.heap<f32>>>, !fir.dscope) -> (!fir.ref<!fir.box<!fir.heap<f32>>>, !fir.ref<!fir.box<!fir.heap<f32>>>)
+  %8:2 = hlfir.declare %arg2 dummy_scope %0 {fortran_attrs = #fir.var_attrs<target>, uniq_name = "_QFtestEt_arr"} : (!fir.box<!fir.array<?xf32>>, !fir.dscope) -> (!fir.box<!fir.array<?xf32>>, !fir.box<!fir.array<?xf32>>)
+  %9:2 = hlfir.declare %arg6 dummy_scope %0 {test.ptr="v", uniq_name = "_QFtestEv"} : (!fir.ref<f32>, !fir.dscope) -> (!fir.ref<f32>, !fir.ref<f32>)
+  %10 = fir.load %4#0 : !fir.ref<!fir.box<!fir.ptr<f32>>>
+  %11 = fir.box_addr %10 {test.ptr="p0.tgt"} : (!fir.box<!fir.ptr<f32>>) -> !fir.ptr<f32>
+  %12 = fir.load %5#0 : !fir.ref<!fir.box<!fir.ptr<f32>>>
+  %13 = fir.box_addr %12 {test.ptr="p1.tgt"}  : (!fir.box<!fir.ptr<f32>>) -> !fir.ptr<f32>
+  %c1 = arith.constant 1 : index
+  %14 = hlfir.designate %2#0 (%c1) {test.ptr="arr(1)"} : (!fir.box<!fir.array<?xf32>>, index) -> !fir.ref<f32>
+  %c1_0 = arith.constant 1 : index
+  %15 = hlfir.designate %8#0 (%c1_0) {test.ptr="t_arr(1)"} : (!fir.box<!fir.array<?xf32>>, index) -> !fir.ref<f32>
+  %16 = fir.load %1#0 : !fir.ref<!fir.box<!fir.heap<f32>>>
+  %17 = fir.box_addr %16 {test.ptr="alloc.tgt"} : (!fir.box<!fir.heap<f32>>) -> !fir.heap<f32>
+  %18 = fir.load %7#0 : !fir.ref<!fir.box<!fir.heap<f32>>>
+  %19 = fir.box_addr %18 {test.ptr="t_alloc.tgt"} : (!fir.box<!fir.heap<f32>>) -> !fir.heap<f32>
+  return
+}
+
+func.func @_QPtest.fir(%arg0: !fir.ref<!fir.box<!fir.ptr<f32>>> {fir.bindc_name = "p1"}, %arg1: !fir.box<!fir.array<?xf32>> {fir.bindc_name = "arr"}, %arg2: !fir.box<!fir.array<?xf32>> {fir.bindc_name = "t_arr", fir.target}, %arg3: !fir.ref<!fir.box<!fir.heap<f32>>> {fir.bindc_name = "alloc"}, %arg4: !fir.ref<!fir.box<!fir.heap<f32>>> {fir.bindc_name = "t_alloc", fir.target}, %arg5: !fir.ref<f32> {fir.bindc_name = "t", fir.target}, %arg6: !fir.ref<f32> {fir.bindc_name = "v"}) {
+  %0 = fir.dummy_scope : !fir.dscope
+  %1 = fir.declare %arg3 dummy_scope %0 {test.ptr = "alloc.fir", fortran_attrs = #fir.var_attrs<allocatable>, uniq_name = "_QFtestEalloc"} : (!fir.ref<!fir.box<!fir.heap<f32>>>, !fir.dscope) -> !fir.ref<!fir.box<!fir.heap<f32>>>
+  %2 = fir.declare %arg1 dummy_scope %0 {uniq_name = "_QFtestEarr"} : (!fir.box<!fir.array<?xf32>>, !fir.dscope) -> !fir.box<!fir.array<?xf32>>
+  %3 = fir.rebox %2 : (!fir.box<!fir.array<?xf32>>) -> !fir.box<!fir.array<?xf32>>
+  %4 = fir.alloca !fir.box<!fir.ptr<f32>> {bindc_name = "p0", uniq_name = "_QFtestEp0"}
+  %5 = fir.declare %4 {test.ptr = "p0.fir", fortran_attrs = #fir.var_attrs<pointer>, uniq_name = "_QFtestEp0"} : (!fir.ref<!fir.box<!fir.ptr<f32>>>) -> !fir.ref<!fir.box<!fir.ptr<f32>>>
+  %6 = fir.declare %arg0 dummy_scope %0 {test.ptr = "p1.fir", fortran_attrs = #fir.var_attrs<pointer>, uniq_name = "_QFtestEp1"} : (!fir.ref<!fir.box<!fir.ptr<f32>>>, !fir.dscope) -> !fir.ref<!fir.box<!fir.ptr<f32>>>
+  %7 = fir.declare %arg5 dummy_scope %0 {test.ptr = "t.fir", fortran_attrs = #fir.var_attrs<target>, uniq_name = "_QFtestEt"} : (!fir.ref<f32>, !fir.dscope) -> !fir.ref<f32>
+  %8 = fir.declare %arg4 dummy_scope %0 {fortran_attrs = #fir.var_attrs<allocatable, target>, uniq_name = "_QFtestEt_alloc"} : (!fir.ref<!fir.box<!fir.heap<f32>>>, !fir.dscope) -> !fir.ref<!fir.box<!fir.heap<f32>>>
+  %9 = fir.declare %arg2 dummy_scope %0 {fortran_attrs = #fir.var_attrs<target>, uniq_name = "_QFtestEt_arr"} : (!fir.box<!fir.array<?xf32>>, !fir.dscope) -> !fir.box<!fir.array<?xf32>>
+  %10 = fir.rebox %9 : (!fir.box<!fir.array<?xf32>>) -> !fir.box<!fir.array<?xf32>>
+  %11 = fir.declare %arg6 dummy_scope %0 {test.ptr = "v.fir", uniq_name = "_QFtestEv"} : (!fir.ref<f32>, !fir.dscope) -> !fir.ref<f32>
+  %12 = fir.load %5 : !fir.ref<!fir.box<!fir.ptr<f32>>>
+  %13 = fir.box_addr %12 {test.ptr = "p0.tgt.fir"} : (!fir.box<!fir.ptr<f32>>) -> !fir.ptr<f32>
+  %14 = fir.load %6 : !fir.ref<!fir.box<!fir.ptr<f32>>>
+  %15 = fir.box_addr %14 {test.ptr = "p1.tgt.fir"} : (!fir.box<!fir.ptr<f32>>) -> !fir.ptr<f32>
+  %c1 = arith.constant 1 : index
+  %16 = fir.array_coor %3 %c1 {test.ptr="arr(1).fir"} : (!fir.box<!fir.array<?xf32>>, index) -> !fir.ref<f32>
+  %c1_0 = arith.constant 1 : index
+  %17 = fir.array_coor %10 %c1_0 {test.ptr="t_arr(1).fir"} : (!fir.box<!fir.array<?xf32>>, index) -> !fir.ref<f32>
+  %18 = fir.load %1 : !fir.ref<!fir.box<!fir.heap<f32>>>
+  %19 = fir.box_addr %18 {test.ptr = "alloc.tgt.fir"} : (!fir.box<!fir.heap<f32>>) -> !fir.heap<f32>
+  %20 = fir.load %8 : !fir.ref<!fir.box<!fir.heap<f32>>>
+  %21 = fir.box_addr %20 {test.ptr = "t_alloc.tgt.fir"} : (!fir.box<!fir.heap<f32>>) -> !fir.heap<f32>
+  return
+}
+
+// -----
+
+// Repeat above test except compare the local pointer against globals.
+
+// module m
+//   real, pointer :: p1
+//   real :: arr(2)
+//   real, target :: t_arr(2)
+//   real, allocatable :: alloc
+//   real, allocatable, target :: t_alloc
+//   real, target :: t
+//   real :: v
+// contains
+//   subroutine test()
+//     real, pointer :: p0
+//   end subroutine test
+// end module m
+
+// CHECK-LABEL: Testing : "_QMmPtest"
+
+// 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: p0.tgt#0 <-> p1.tgt#0: MayAlias
+// CHECK-DAG: t#0 <-> p0.tgt#0: MayAlias
+// CHECK-DAG: t#0 <-> p1.tgt#0: MayAlias
+// CHECK-DAG: v#0 <-> p0.tgt#0: NoAlias
+// CHECK-DAG: v#0 <-> p1.tgt#0: NoAlias
+// CHECK-DAG: p0.tgt.fir#0 <-> p1.tgt.fir#0: MayAlias
+// CHECK-DAG: t.fir#0 <-> p0.tgt.fir#0: MayAlias
+// CHECK-DAG: t.fir#0 <-> p1.tgt.fir#0: MayAlias
+// CHECK-DAG: v.fir#0 <-> p0.tgt.fir#0: NoAlias
+// CHECK-DAG: v.fir#0 <-> p1.tgt.fir#0: NoAlias
+
+// The address in a pointer cannot alias the address of a pointer.
+// CHECK-DAG: p0#0 <-> p0.tgt#0: NoAlias
+// CHECK-DAG: p0#0 <-> p1.tgt#0: NoAlias
+// CHECK-DAG: p1#0 <-> p0.tgt#0: NoAlias
+// CHECK-DAG: p1#0 <-> p1.tgt#0: NoAlias
+// CHECK-DAG: p0.fir#0 <-> p0.tgt.fir#0: NoAlias
+// CHECK-DAG: p0.fir#0 <-> p1.tgt.fir#0: NoAlias
+// CHECK-DAG: p1.fir#0 <-> p0.tgt.fir#0: NoAlias
+// CHECK-DAG: p1.fir#0 <-> 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 arr(1) as an address that
+// was loaded from a pointer and that could alias something.  However, t_arr is
+// a target.
+// CHECK-DAG: p0.tgt#0 <-> arr(1)#0: NoAlias
+// CHECK-DAG: p0.tgt#0 <-> t_arr(1)#0: MayAlias
+// CHECK-DAG: p0.tgt.fir#0 <-> arr(1).fir#0: NoAlias
+// CHECK-DAG: p0.tgt.fir#0 <-> t_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_alloc is a target.
+// CHECK-DAG: p0.tgt#0 <-> alloc.tgt#0: NoAlias
+// CHECK-DAG: p0.tgt#0 <-> t_alloc.tgt#0: MayAlias
+// CHECK-DAG: p0.tgt.fir#0 <-> alloc.tgt.fir#0: NoAlias
+// CHECK-DAG: p0.tgt.fir#0 <-> t_alloc.tgt.fir#0: MayAlias
+
+// The address in an allocatable cannot alias the address of that allocatable.
+// CHECK-DAG: alloc#0 <-> alloc.tgt#0: NoAlias
+// CHECK-DAG: alloc.fir#0 <-> alloc.tgt.fir#0: NoAlias
+
+func.func @_QMmPtest() {
+  %0 = fir.address_of(@_QMmEalloc) : !fir.ref<!fir.box<!fir.heap<f32>>>
+  %1:2 = hlfir.declare %0 {test.ptr="alloc", fortran_attrs = #fir.var_attrs<allocatable>, uniq_name = "_QMmEalloc"} : (!fir.ref<!fir.box<!fir.heap<f32>>>) -> (!fir.ref<!fir.box<!fir.heap<f32>>>, !fir.ref<!fir.box<!fir.heap<f32>>>)
+  %2 = fir.address_of(@_QMmEarr) : !fir.ref<!fir.array<2xf32>>
+  %c2 = arith.constant 2 : index
+  %3 = fir.shape %c2 : (index) -> !fir.shape<1>
+  %4:2 = hlfir.declare %2(%3) {uniq_name = "_QMmEarr"} : (!fir.ref<!fir.array<2xf32>>, !fir.shape<1>) -> (!fir.ref<!fir.array<2xf32>>, !fir.ref<!fir.array<2xf32>>)
+  %5 = fir.address_of(@_QMmEp1) : !fir.ref<!fir.box<!fir.ptr<f32>>>
+  %6:2 = hlfir.declare %5 {test.ptr="p1", fortran_attrs = #fir.var_attrs<pointer>, uniq_name = "_QMmEp1"} : (!fir.ref<!fir.box<!fir.ptr<f32>>>) -> (!fir.ref<!fir.box<!fir.ptr<f32>>>, !fir.ref<!fir.box<!fir.ptr<f32>>>)
+  %7 = fir.address_of(@_QMmEt) : !fir.ref<f32>
+  %8:2 = hlfir.declare %7 {test.ptr="t", fortran_attrs = #fir.var_attrs<target>, uniq_name = "_QMmEt"} : (!fir.ref<f32>) -> (!fir.ref<f32>, !fir.ref<f32>)
+  %9 = fir.address_of(@_QMmEt_alloc) : !fir.ref<!fir.box<!fir.heap<f32>>>
+  %10:2 = hlfir.declare %9 {fortran_attrs = #fir.var_attrs<allocatable, target>, uniq_name = "_QMmEt_alloc"} : (!fir.ref<!fir.box<!fir.heap<f32>>>) -> (!fir.ref<!fir.box<!fir.heap<f32>>>, !fir.ref<!fir.box<!fir.heap<f32>>>)
+  %11 = fir.address_of(@_QMmEt_arr) : !fir.ref<!fir.array<2xf32>>
+  %c2_0 = arith.constant 2 : index
+  %12 = fir.shape %c2_0 : (index) -> !fir.shape<1>
+  %13:2 = hlfir.declare %11(%12) {fortran_attrs = #fir.var_attrs<target>, uniq_name = "_QMmEt_arr"} : (!fir.ref<!fir.array<2xf32>>, !fir.shape<1>) -> (!fir.ref<!fir.array<2xf32>>, !fir.ref<!fir.array<2xf32>>)
+  %14 = fir.address_of(@_QMmEv) : !fir.ref<f32>
+  %15:2 = hlfir.declare %14 {test.ptr="v", uniq_name = "_QMmEv"} : (!fir.ref<f32>) -> (!fir.ref<f32>, !fir.ref<f32>)
+  %16 = fir.alloca !fir.box<!fir.ptr<f32>> {bindc_name = "p0", uniq_name = "_QMmFtestEp0"}
+  %17:2 = hlfir.declare %16 {test.ptr="p0", fortran_attrs = #fir.var_attrs<pointer>, uniq_name = "_QMmFtestEp0"} : (!fir.ref<!fir.box<!fir.ptr<f32>>>) -> (!fir.ref<!fir.box<!fir.ptr<f32>>>, !fir.ref<!fir.box<!fir.ptr<f32>>>)
+  %18 = fir.load %17#0 : !fir.ref<!fir.box<!fir.ptr<f32>>>
+  %19 = fir.box_addr %18 {test.ptr="p0.tgt"} : (!fir.box<!fir.ptr<f32>>) -> !fir.ptr<f32>
+  %20 = fir.load %6#0 : !fir.ref<!fir.box<!fir.ptr<f32>>>
+  %21 = fir.box_addr %20 {test.ptr="p1.tgt"}  : (!fir.box<!fir.ptr<f32>>) -> !fir.ptr<f32>
+  %c1 = arith.constant 1 : index
+  %22 = hlfir.designate %4#0 (%c1) {test.ptr="arr(1)"} : (!fir.ref<!fir.array<2xf32>>, index) -> !fir.ref<f32>
+  %c1_1 = arith.constant 1 : index
+  %23 = hlfir.designate %13#0 (%c1_1) {test.ptr="t_arr(1)"} : (!fir.ref<!fir.array<2xf32>>, index) -> !fir.ref<f32>
+  %24 = fir.load %1#0 : !fir.ref<!fir.box<!fir.heap<f32>>>
+  %25 = fir.box_addr %24 {test.ptr="alloc.tgt"} : (!fir.box<!fir.heap<f32>>) -> !fir.heap<f32>
+  %26 = fir.load %10#0 : !fir.ref<!fir.box<!fir.heap<f32>>>
+  %27 = fir.box_addr %26 {test.ptr="t_alloc.tgt"} : (!fir.box<!fir.heap<f32>>) -> !fir.heap<f32>
+  return
+}
+
+func.func @_QMmPtest.fir() {
+  %0 = fir.address_of(@_QMmEalloc) : !fir.ref<!fir.box<!fir.heap<f32>>>
+  %1 = fir.declare %0 {test.ptr = "alloc.fir", fortran_attrs = #fir.var_attrs<allocatable>, uniq_name = "_QMmEalloc"} : (!fir.ref<!fir.box<!fir.heap<f32>>>) -> !fir.ref<!fir.box<!fir.heap<f32>>>
+  %2 = fir.address_of(@_QMmEarr) : !fir.ref<!fir.array<2xf32>>
+  %c2 = arith.constant 2 : index
+  %3 = fir.shape %c2 : (index) -> !fir.shape<1>
+  %4 = fir.declare %2(%3) {uniq_name = "_QMmEarr"} : (!fir.ref<!fir.array<2xf32>>, !fir.shape<1>) -> !fir.ref<!fir.array<2xf32>>
+  %5 = fir.address_of(@_QMmEp1) : !fir.ref<!fir.box<!fir.ptr<f32>>>
+  %6 = fir.declare %5 {test.ptr = "p1.fir", fortran_attrs = #fir.var_attrs<pointer>, uniq_name = "_QMmEp1"} : (!fir.ref<!fir.box<!fir.ptr<f32>>>) -> !fir.ref<!fir.box<!fir.ptr<f32>>>
+  %7 = fir.address_of(@_QMmEt) : !fir.ref<f32>
+  %8 = fir.declare %7 {test.ptr = "t.fir", fortran_attrs = #fir.var_attrs<target>, uniq_name = "_QMmEt"} : (!fir.ref<f32>) -> !fir.ref<f32>
+  %9 = fir.address_of(@_QMmEt_alloc) : !fir.ref<!fir.box<!fir.heap<f32>>>
+  %10 = fir.declare %9 {fortran_attrs = #fir.var_attrs<allocatable, target>, uniq_name = "_QMmEt_alloc"} : (!fir.ref<!fir.box<!fir.heap<f32>>>) -> !fir.ref<!fir.box<!fir.heap<f32>>>
+  %11 = fir.address_of(@_QMmEt_arr) : !fir.ref<!fir.array<2xf32>>
+  %c2_0 = arith.constant 2 : index
+  %12 = fir.shape %c2_0 : (index) -> !fir.shape<1>
+  %13 = fir.declare %11(%12) {fortran_attrs = #fir.var_attrs<target>, uniq_name = "_QMmEt_arr"} : (!fir.ref<!fir.array<2xf32>>, !fir.shape<1>) -> !fir.ref<!fir.array<2xf32>>
+  %14 = fir.address_of(@_QMmEv) : !fir.ref<f32>
+  %15 = fir.declare %14 {test.ptr = "v.fir", uniq_name = "_QMmEv"} : (!fir.ref<f32>) -> !fir.ref<f32>
+  %16 = fir.alloca !fir.box<!fir.ptr<f32>> {bindc_name = "p0", uniq_name = "_QMmFtestEp0"}
+  %17 = fir.declare %16 {test.ptr = "p0.fir", fortran_attrs = #fir.var_attrs<pointer>, uniq_name = "_QMmFtestEp0"} : (!fir.ref<!fir.box<!fir.ptr<f32>>>) -> !fir.ref<!fir.box<!fir.ptr<f32>>>
+  %18 = fir.load %17 : !fir.ref<!fir.box<!fir.ptr<f32>>>
+  %19 = fir.box_addr %18 {test.ptr = "p0.tgt.fir"} : (!fir.box<!fir.ptr<f32>>) -> !fir.ptr<f32>
+  %20 = fir.load %6 : !fir.ref<!fir.box<!fir.ptr<f32>>>
+  %21 = fir.box_addr %20 {test.ptr = "p1.tgt.fir"} : (!fir.box<!fir.ptr<f32>>) -> !fir.ptr<f32>
+  %c1 = arith.constant 1 : index
+  %22 = fir.array_coor %4(%3) %c1 {test.ptr="arr(1).fir"} : (!fir.ref<!fir.array<2xf32>>, !fir.shape<1>, index) -> !fir.ref<f32>
+  %c1_1 = arith.constant 1 : index
+  %23 = fir.array_coor %13(%12) %c1_1 {test.ptr="t_arr(1).fir"} : (!fir.ref<!fir.array<2xf32>>, !fir.shape<1>, index) -> !fir.ref<f32>
+  %24 = fir.load %1 : !fir.ref<!fir.box<!fir.heap<f32>>>
+  %25 = fir.box_addr %24 {test.ptr = "alloc.tgt.fir"} : (!fir.box<!fir.heap<f32>>) -> !fir.heap<f32>
+  %26 = fir.load %10 : !fir.ref<!fir.box<!fir.heap<f32>>>
+  %27 = fir.box_addr %26 {test.ptr = "t_alloc.tgt.fir"} : (!fir.box<!fir.heap<f32>>) -> !fir.heap<f32>
+  return
+}

>From 869c7563267ed592023f17b381962b30d66b5744 Mon Sep 17 00:00:00 2001
From: "Joel E. Denny" <jdenny.ornl at gmail.com>
Date: Tue, 26 Nov 2024 18:03:31 -0500
Subject: [PATCH 2/3] Move getOriginalDef back to where it was, as requested

---
 .../lib/Optimizer/Analysis/AliasAnalysis.cpp  | 51 ++++++++++---------
 1 file changed, 28 insertions(+), 23 deletions(-)

diff --git a/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp b/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp
index 284b3dadbcef96..61d8fb4ca23ee3 100644
--- a/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp
+++ b/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp
@@ -31,6 +31,34 @@ using namespace mlir;
 // AliasAnalysis: alias
 //===----------------------------------------------------------------------===//
 
+namespace fir {
+  static AliasAnalysis::Source::Attributes
+  getAttrsFromVariable(fir::FortranVariableOpInterface var);
+}
+
+/// Temporary function to skip through all the no op operations
+/// TODO: Generalize support of fir.load
+static mlir::Value
+getOriginalDef(mlir::Value v,
+               fir::AliasAnalysis::Source::Attributes &attributes,
+               bool &isCapturedInInternalProcedure) {
+  mlir::Operation *defOp;
+  bool breakFromLoop = false;
+  while (!breakFromLoop && (defOp = v.getDefiningOp())) {
+    llvm::TypeSwitch<Operation *>(defOp)
+        .Case<fir::ConvertOp>([&](fir::ConvertOp op) { v = op.getValue(); })
+        .Case<fir::DeclareOp, hlfir::DeclareOp>([&](auto op) {
+          v = op.getMemref();
+          auto varIf = llvm::cast<fir::FortranVariableOpInterface>(defOp);
+          attributes |= fir::getAttrsFromVariable(varIf);
+          isCapturedInInternalProcedure |=
+              varIf.isCapturedInInternalProcedure();
+        })
+        .Default([&](auto op) { breakFromLoop = true; });
+  }
+  return v;
+}
+
 namespace fir {
 
 void AliasAnalysis::Source::print(llvm::raw_ostream &os) const {
@@ -482,29 +510,6 @@ static Value getPrivateArg(omp::BlockArgOpenMPOpInterface &argIface,
   return privateArg;
 }
 
-/// Temporary function to skip through all the no op operations
-/// TODO: Generalize support of fir.load
-static mlir::Value
-getOriginalDef(mlir::Value v,
-               fir::AliasAnalysis::Source::Attributes &attributes,
-               bool &isCapturedInInternalProcedure) {
-  mlir::Operation *defOp;
-  bool breakFromLoop = false;
-  while (!breakFromLoop && (defOp = v.getDefiningOp())) {
-    llvm::TypeSwitch<Operation *>(defOp)
-        .Case<fir::ConvertOp>([&](fir::ConvertOp op) { v = op.getValue(); })
-        .Case<fir::DeclareOp, hlfir::DeclareOp>([&](auto op) {
-          v = op.getMemref();
-          auto varIf = llvm::cast<fir::FortranVariableOpInterface>(defOp);
-          attributes |= getAttrsFromVariable(varIf);
-          isCapturedInInternalProcedure |=
-              varIf.isCapturedInInternalProcedure();
-        })
-        .Default([&](auto op) { breakFromLoop = true; });
-  }
-  return v;
-}
-
 AliasAnalysis::Source AliasAnalysis::getSource(mlir::Value v,
                                                bool getLastInstantiationPoint) {
   auto *defOp = v.getDefiningOp();

>From e1fcee00c716eca85721d363c7f29e73df3a09f3 Mon Sep 17 00:00:00 2001
From: "Joel E. Denny" <jdenny.ornl at gmail.com>
Date: Tue, 26 Nov 2024 18:11:01 -0500
Subject: [PATCH 3/3] Apply clang-format

---
 flang/lib/Optimizer/Analysis/AliasAnalysis.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp b/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp
index 61d8fb4ca23ee3..05ca52767022e5 100644
--- a/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp
+++ b/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp
@@ -32,8 +32,8 @@ using namespace mlir;
 //===----------------------------------------------------------------------===//
 
 namespace fir {
-  static AliasAnalysis::Source::Attributes
-  getAttrsFromVariable(fir::FortranVariableOpInterface var);
+static AliasAnalysis::Source::Attributes
+getAttrsFromVariable(fir::FortranVariableOpInterface var);
 }
 
 /// Temporary function to skip through all the no op operations



More information about the flang-commits mailing list