[flang-commits] [flang] [flang] AliasAnalysis: distinguish addr of arg vs. addr in arg (PR #87723)

Joel E. Denny via flang-commits flang-commits at lists.llvm.org
Thu Apr 4 15:31:27 PDT 2024


https://github.com/jdenny-ornl created https://github.com/llvm/llvm-project/pull/87723

For example, in the following program, the relationship between the address *in* arg (dynamically the address of x's alloca) and the address *of* arg (dynamically the address of p's alloca) is not MustAlias, as determined without this patch:

```
subroutine f()
  real, pointer :: p
  real, target :: x
  p => x
  call g(p)
end subroutine f
subroutine g(arg)
  real, pointer :: arg
end subroutine g
```

Generally extend test coverage for HLFIR-based alias analysis for addresses extracted from pointers.

>From 91def8cd94aadf6f1909c63277aea4364c8907e1 Mon Sep 17 00:00:00 2001
From: "Joel E. Denny" <jdenny.ornl at gmail.com>
Date: Thu, 4 Apr 2024 12:41:05 -0400
Subject: [PATCH] [flang] AliasAnalysis: distinguish addr of arg vs. addr in
 arg

For example, in the following program, the relationship between the
address *in* arg (dynamically the address of x's alloca) and the
address *of* arg (dynamically the address of p's alloca) is not
MustAlias, as determined without this patch:

```
subroutine f()
  real, pointer :: p
  real, target :: x
  p => x
  call g(p)
end subroutine f
subroutine g(arg)
  real, pointer :: arg
end subroutine g
```

Generally extend test coverage for HLFIR-based alias analysis for
addresses extracted from pointers.
---
 .../flang/Optimizer/Analysis/AliasAnalysis.h  |  4 +-
 .../lib/Optimizer/Analysis/AliasAnalysis.cpp  | 20 +++--
 .../AliasAnalysis/alias-analysis-2.fir        |  2 +-
 .../alias-analysis-box-addr-load/arg.fir      | 90 +++++++++++++++++++
 4 files changed, 108 insertions(+), 8 deletions(-)
 create mode 100644 flang/test/Analysis/AliasAnalysis/alias-analysis-box-addr-load/arg.fir

diff --git a/flang/include/flang/Optimizer/Analysis/AliasAnalysis.h b/flang/include/flang/Optimizer/Analysis/AliasAnalysis.h
index dfcafe88fee1b5..dd4eb363cc7277 100644
--- a/flang/include/flang/Optimizer/Analysis/AliasAnalysis.h
+++ b/flang/include/flang/Optimizer/Analysis/AliasAnalysis.h
@@ -36,8 +36,8 @@ struct AliasAnalysis {
              /// Represents memory allocated outside of a function
              /// and passed to the function via host association tuple.
              HostAssoc,
-             /// Represents direct memory access whose source cannot be further
-             /// determined
+             /// Memory address retrieved from a box, perhaps from a global or
+             /// an argument.
              Direct,
              /// Represents memory allocated by unknown means and
              /// with the memory address defined by a memory reading
diff --git a/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp b/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp
index e144640081cbf3..f0af0dd547f980 100644
--- a/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp
+++ b/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp
@@ -91,8 +91,14 @@ AliasResult AliasAnalysis::alias(Value lhs, Value rhs) {
   LLVM_DEBUG(llvm::dbgs() << "AliasAnalysis::alias\n";
              llvm::dbgs() << "  lhs: " << lhs << "\n";
              llvm::dbgs() << "  lhsSrc: " << lhsSrc << "\n";
+             llvm::dbgs() << "  lhsSrc kind: " << EnumToString(lhsSrc.kind) << "\n";
+             llvm::dbgs() << "  lhsSrc pointer: " << lhsSrc.attributes.test(Attribute::Pointer) << "\n";
+             llvm::dbgs() << "  lhsSrc target: " << lhsSrc.attributes.test(Attribute::Target) << "\n";
              llvm::dbgs() << "  rhs: " << rhs << "\n";
              llvm::dbgs() << "  rhsSrc: " << rhsSrc << "\n";
+             llvm::dbgs() << "  rhsSrc kind: " << EnumToString(rhsSrc.kind) << "\n";
+             llvm::dbgs() << "  rhsSrc pointer: " << rhsSrc.attributes.test(Attribute::Pointer) << "\n";
+             llvm::dbgs() << "  rhsSrc target: " << rhsSrc.attributes.test(Attribute::Target) << "\n";
              llvm::dbgs() << "\n";);
 
   // Indirect case currently not handled. Conservatively assume
@@ -101,8 +107,10 @@ AliasResult AliasAnalysis::alias(Value lhs, Value rhs) {
     return AliasResult::MayAlias;
   }
 
-  // SourceKind::Direct is set for the addresses wrapped in a global boxes.
-  // ie: fir.global @_QMpointersEp : !fir.box<!fir.ptr<f32>>
+  // SourceKind::Direct is set for the addresses wrapped in a box, perhaps from
+  // a global or an argument.
+  // e.g.: fir.global @_QMpointersEp : !fir.box<!fir.ptr<f32>>
+  // e.g.: %arg0: !fir.ref<!fir.box<!fir.ptr<f32>>>
   // Though nothing is known about them, they would only alias with targets or
   // pointers
   bool directSourceToNonTargetOrPointer = false;
@@ -399,16 +407,18 @@ AliasAnalysis::Source AliasAnalysis::getSource(mlir::Value v) {
   if (!defOp && type == SourceKind::Unknown)
     // Check if the memory source is coming through a dummy argument.
     if (isDummyArgument(v)) {
-      type = SourceKind::Argument;
       ty = v.getType();
       if (fir::valueHasFirAttribute(v, fir::getTargetAttrName()))
         attributes.set(Attribute::Target);
-
       if (Source::isPointerReference(ty))
         attributes.set(Attribute::Pointer);
+      if (followBoxAddr && attributes.test(Attribute::Pointer))
+        type = SourceKind::Direct;
+      else
+        type = SourceKind::Argument;
     }
 
-  if (type == SourceKind::Global || type == SourceKind::Direct)
+  if (global)
     return {global, type, ty, attributes, approximateSource};
 
   return {v, type, ty, attributes, approximateSource};
diff --git a/flang/test/Analysis/AliasAnalysis/alias-analysis-2.fir b/flang/test/Analysis/AliasAnalysis/alias-analysis-2.fir
index 31459ef21d947c..d915ba9d27905a 100644
--- a/flang/test/Analysis/AliasAnalysis/alias-analysis-2.fir
+++ b/flang/test/Analysis/AliasAnalysis/alias-analysis-2.fir
@@ -44,7 +44,7 @@
 // pointer arguments
 // CHECK-DAG: arg2.addr#0 <-> func.region0#0: MayAlias
 // CHECK-DAG: arg2.addr#0 <-> func.region0#1: MayAlias
-// CHECK-DAG: arg2.addr#0 <-> func.region0#2: MustAlias
+// CHECK-DAG: arg2.addr#0 <-> func.region0#2: MayAlias
 // CHECK-DAG: boxp1.addr#0 <-> arg2.addr#0: MayAlias
 
 func.func @_QFPtest(%arg0: !fir.ref<f32> {fir.bindc_name = "v1", fir.target}, %arg1: !fir.ref<f32> {fir.bindc_name = "v2", fir.target}, %arg2: !fir.ref<!fir.box<!fir.ptr<f32>>> ) attributes {test.ptr = "func"} {
diff --git a/flang/test/Analysis/AliasAnalysis/alias-analysis-box-addr-load/arg.fir b/flang/test/Analysis/AliasAnalysis/alias-analysis-box-addr-load/arg.fir
new file mode 100644
index 00000000000000..de1b478fa9599e
--- /dev/null
+++ b/flang/test/Analysis/AliasAnalysis/alias-analysis-box-addr-load/arg.fir
@@ -0,0 +1,90 @@
+// Check aliasing with the address passed via a pointer dummy argument.
+
+// Use --mlir-disable-threading so that the AA queries are serialized
+// as well as its diagnostic output.
+// RUN: fir-opt %s \
+// RUN:   -pass-pipeline='builtin.module(func.func(test-fir-alias-analysis))' \
+// RUN:   --mlir-disable-threading 2>&1 | FileCheck %s
+
+// subroutine test(p0, p1, arr, t_arr, alloc, t_alloc)
+//   real, pointer :: p0, p1
+//   real :: arr(:)
+//   real, target :: t_arr(:)
+//   real, allocatable :: alloc
+//   real, allocatable, target :: t_alloc
+//   real, target :: t
+//   real :: v
+//   v = p0
+//   v = p1
+//   v = arr(1)
+//   v = t_arr(1)
+//   v = alloc
+//   v = t_alloc
+// 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: t.addr#0 <-> p0.tgt_addr#0: MayAlias
+// CHECK-DAG: t.addr#0 <-> p1.tgt_addr#0: MayAlias
+// CHECK-DAG: v.addr#0 <-> p0.tgt_addr#0: NoAlias
+// CHECK-DAG: v.addr#0 <-> p1.tgt_addr#0: NoAlias
+// CHECK-DAG: p0.tgt_addr#0 <-> p1.tgt_addr#0: MayAlias
+
+// Determining whether the address *in* a pointer can alias the address *of* a
+// pointer is not yet handled.  In the past, when it was the same pointer, that
+// relationship was mistakenly determined to be MustAlias.
+// CHECK-DAG: p0.tgt_addr#0 <-> func.region0#0: MayAlias
+// CHECK-DAG: p0.tgt_addr#0 <-> func.region0#1: MayAlias
+// CHECK-DAG: p1.tgt_addr#0 <-> func.region0#0: MayAlias
+// CHECK-DAG: p1.tgt_addr#0 <-> func.region0#1: MayAlias
+
+// For some cases, AliasAnalysis analyzes hlfir.designate like fir.box_addr, so
+// make sure it doesn't mistakenly see arr(1).addr as an address that was loaded
+// from a pointer and that could alias something.  However, t_arr is a target.
+// CHECK-DAG: p0.tgt_addr#0 <-> arr(1).addr#0: NoAlias
+// CHECK-DAG: p0.tgt_addr#0 <-> t_arr(1).addr#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_addr#0 <-> alloc.tgt_addr#0: NoAlias
+// CHECK-DAG: p0.tgt_addr#0 <-> t_alloc.tgt_addr#0: MayAlias
+
+func.func @_QPtest(%arg0: !fir.ref<!fir.box<!fir.ptr<f32>>> {fir.bindc_name = "p0"}, %arg1: !fir.ref<!fir.box<!fir.ptr<f32>>> {fir.bindc_name = "p1"}, %arg2: !fir.box<!fir.array<?xf32>> {fir.bindc_name = "arr"}, %arg3: !fir.box<!fir.array<?xf32>> {fir.bindc_name = "t_arr", fir.target}, %arg4: !fir.ref<!fir.box<!fir.heap<f32>>> {fir.bindc_name = "alloc"}, %arg5: !fir.ref<!fir.box<!fir.heap<f32>>> {fir.bindc_name = "t_alloc", fir.target}) attributes {test.ptr="func"} {
+  %0:2 = hlfir.declare %arg4 {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>>>)
+  %1:2 = hlfir.declare %arg2 {uniq_name = "_QFtestEarr"} : (!fir.box<!fir.array<?xf32>>) -> (!fir.box<!fir.array<?xf32>>, !fir.box<!fir.array<?xf32>>)
+  %2:2 = hlfir.declare %arg0 {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>>>)
+  %3:2 = hlfir.declare %arg1 {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>>>)
+  %4 = fir.alloca f32 {bindc_name = "t", fir.target, uniq_name = "_QFtestEt"}
+  %5:2 = hlfir.declare %4 {fortran_attrs = #fir.var_attrs<target>, uniq_name = "_QFtestEt", test.ptr="t.addr"} : (!fir.ref<f32>) -> (!fir.ref<f32>, !fir.ref<f32>)
+  %6:2 = hlfir.declare %arg5 {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>>>)
+  %7:2 = hlfir.declare %arg3 {fortran_attrs = #fir.var_attrs<target>, uniq_name = "_QFtestEt_arr"} : (!fir.box<!fir.array<?xf32>>) -> (!fir.box<!fir.array<?xf32>>, !fir.box<!fir.array<?xf32>>)
+  %8 = fir.alloca f32 {bindc_name = "v", uniq_name = "_QFtestEv"}
+  %9:2 = hlfir.declare %8 {uniq_name = "_QFtestEv", test.ptr="v.addr"} : (!fir.ref<f32>) -> (!fir.ref<f32>, !fir.ref<f32>)
+  %10 = fir.load %2#0 : !fir.ref<!fir.box<!fir.ptr<f32>>>
+  %11 = fir.box_addr %10 {test.ptr="p0.tgt_addr"} : (!fir.box<!fir.ptr<f32>>) -> !fir.ptr<f32>
+  %12 = fir.load %11 : !fir.ptr<f32>
+  hlfir.assign %12 to %9#0 : f32, !fir.ref<f32>
+  %13 = fir.load %3#0 : !fir.ref<!fir.box<!fir.ptr<f32>>>
+  %14 = fir.box_addr %13 {test.ptr="p1.tgt_addr"} : (!fir.box<!fir.ptr<f32>>) -> !fir.ptr<f32>
+  %15 = fir.load %14 : !fir.ptr<f32>
+  hlfir.assign %15 to %9#0 : f32, !fir.ref<f32>
+  %c1 = arith.constant 1 : index
+  %16 = hlfir.designate %1#0 (%c1) {test.ptr="arr(1).addr"} : (!fir.box<!fir.array<?xf32>>, index) -> !fir.ref<f32>
+  %17 = fir.load %16 : !fir.ref<f32>
+  hlfir.assign %17 to %9#0 : f32, !fir.ref<f32>
+  %c1_0 = arith.constant 1 : index
+  %18 = hlfir.designate %7#0 (%c1_0) {test.ptr="t_arr(1).addr"} : (!fir.box<!fir.array<?xf32>>, index) -> !fir.ref<f32>
+  %19 = fir.load %18 : !fir.ref<f32>
+  hlfir.assign %19 to %9#0 : f32, !fir.ref<f32>
+  %20 = fir.load %0#0 : !fir.ref<!fir.box<!fir.heap<f32>>>
+  %21 = fir.box_addr %20 {test.ptr="alloc.tgt_addr"} : (!fir.box<!fir.heap<f32>>) -> !fir.heap<f32>
+  %22 = fir.load %21 : !fir.heap<f32>
+  hlfir.assign %22 to %9#0 : f32, !fir.ref<f32>
+  %23 = fir.load %6#0 : !fir.ref<!fir.box<!fir.heap<f32>>>
+  %24 = fir.box_addr %23 {test.ptr="t_alloc.tgt_addr"} : (!fir.box<!fir.heap<f32>>) -> !fir.heap<f32>
+  %25 = fir.load %24 : !fir.heap<f32>
+  hlfir.assign %25 to %9#0 : f32, !fir.ref<f32>
+  return
+}



More information about the flang-commits mailing list