[flang-commits] [flang] WIP: [flang] AliasAnalysis: Fix pointer component logic (PR #94242)

Joel E. Denny via flang-commits flang-commits at lists.llvm.org
Mon Jun 3 09:23:26 PDT 2024


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

This PR is not yet being proposed for merging.  For now, it is intended to facilitate the discussion of an [RFC on Flang AliasAnalysis pointer component logic](https://discourse.llvm.org/t/rfc-rationale-for-flang-aliasanalysis-pointer-component-logic/79252).

>From 484cb901cb3f5ae934b55629bb8537e42d3a832d Mon Sep 17 00:00:00 2001
From: "Joel E. Denny" <jdenny.ornl at gmail.com>
Date: Tue, 28 May 2024 19:14:22 -0400
Subject: [PATCH 1/2] WIP: [flang] AliasAnalysis: Fix pointer component logic

---
 .../lib/Optimizer/Analysis/AliasAnalysis.cpp  | 30 ++++++++++++-------
 .../AliasAnalysis/alias-analysis-3.fir        | 19 ++++++------
 .../AliasAnalysis/alias-analysis-9.fir        | 12 ++++----
 3 files changed, 34 insertions(+), 27 deletions(-)

diff --git a/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp b/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp
index 9d0d706a85c5e..571b78dc64aa5 100644
--- a/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp
+++ b/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp
@@ -122,6 +122,18 @@ AliasResult AliasAnalysis::alias(Value lhs, Value rhs) {
   }
 
   if (lhsSrc.kind == rhsSrc.kind) {
+    // If the kinds and origins are the same, then lhs and rhs must alias unless
+    // either source is approximate.  Approximate sources are for parts of the
+    // origin, but we don't have info here on which parts and whether they
+    // overlap, so we normally return MayAlias in that case.
+    //
+    // There is an exceptional case: The origins might compare unequal because
+    // only one has !isData().  If that source is approximate and the other is
+    // not, then the former is the source for the address *of* a pointer
+    // component in a composite, and the latter is for the address of that
+    // composite.  As for the address of any composite vs. the address of one of
+    // its components, a store to one can affect a load from the other, so the
+    // result is MayAlias.
     if (lhsSrc.origin == rhsSrc.origin) {
       LLVM_DEBUG(llvm::dbgs()
                  << "  aliasing because same source kind and origin\n");
@@ -129,6 +141,13 @@ AliasResult AliasAnalysis::alias(Value lhs, Value rhs) {
         return AliasResult::MayAlias;
       return AliasResult::MustAlias;
     }
+    if (lhsSrc.origin.u == rhsSrc.origin.u &&
+        ((lhsSrc.approximateSource && !lhsSrc.isData() && !rhsSrc.approximateSource) ||
+         (rhsSrc.approximateSource && !rhsSrc.isData() && !lhsSrc.approximateSource))) {
+      LLVM_DEBUG(llvm::dbgs()
+                 << "  aliasing between composite and pointer component\n");
+      return AliasResult::MayAlias;
+    }
 
     // Two host associated accesses may overlap due to an equivalence.
     if (lhsSrc.kind == SourceKind::HostAssoc) {
@@ -173,17 +192,6 @@ AliasResult AliasAnalysis::alias(Value lhs, Value rhs) {
     return AliasResult::MayAlias;
   }
 
-  // Box for POINTER component inside an object of a derived type
-  // may alias box of a POINTER object, as well as boxes for POINTER
-  // components inside two objects of derived types may alias.
-  if ((src1->isRecordWithPointerComponent() && src2->isTargetOrPointer()) ||
-      (src2->isRecordWithPointerComponent() && src1->isTargetOrPointer()) ||
-      (src1->isRecordWithPointerComponent() &&
-       src2->isRecordWithPointerComponent())) {
-    LLVM_DEBUG(llvm::dbgs() << "  aliasing because of pointer components\n");
-    return AliasResult::MayAlias;
-  }
-
   return AliasResult::NoAlias;
 }
 
diff --git a/flang/test/Analysis/AliasAnalysis/alias-analysis-3.fir b/flang/test/Analysis/AliasAnalysis/alias-analysis-3.fir
index 91829a461dc72..2bf326f2d2af2 100644
--- a/flang/test/Analysis/AliasAnalysis/alias-analysis-3.fir
+++ b/flang/test/Analysis/AliasAnalysis/alias-analysis-3.fir
@@ -16,12 +16,12 @@
 //   end subroutine test
 // end module m
 
-// A composite with a pointer component may alias with a dummy pointer
+// A composite with a pointer component does not alias with a dummy pointer
 // CHECK-LABEL: Testing : "_QMmPtest
-// CHECK: a#0 <-> func.region0#0: MayAlias
+// CHECK: a#0 <-> func.region0#0: NoAlias
 
-// FIXME: a's box cannot alias with raw reference to f32 (x), so MayAlias below must be NoAlias:
-// CHECK: a#0 <-> func.region0#1: MayAlias
+// a's box cannot alias with raw reference to f32 (x)
+// CHECK: a#0 <-> func.region0#1: NoAlias
 
 // pointer_dummy's box cannot alias with raw reference to f32 (x)
 // CHECK: func.region0#0 <-> func.region0#1: NoAlias
@@ -46,7 +46,7 @@ func.func private @_QPtest2(!fir.ref<f32>)
 
 // -----
 
-// A composite with a pointer component may alias with a dummy
+// A composite with a pointer component does not alias with a dummy
 // argument of composite type with a pointer component:
 // module m
 //   type t
@@ -63,7 +63,7 @@ func.func private @_QPtest2(!fir.ref<f32>)
 // end module m
 
 // CHECK-LABEL: Testing : "_QMmPtest"
-// CHECK: a#0 <-> func.region0#0: MayAlias
+// CHECK: a#0 <-> func.region0#0: NoAlias
 
 fir.global @_QMmEa : !fir.type<_QMmTt{pointer_component:!fir.box<!fir.ptr<f32>>}> {
   %0 = fir.undefined !fir.type<_QMmTt{pointer_component:!fir.box<!fir.ptr<f32>>}>
@@ -88,7 +88,7 @@ func.func private @_QPtest2(!fir.ref<f32>)
 // -----
 
 // Two dummy arguments of composite type with a pointer component
-// may alias each other:
+// do not alias each other:
 // module m
 //   type t
 //      real, pointer :: pointer_component
@@ -103,7 +103,7 @@ func.func private @_QPtest2(!fir.ref<f32>)
 // end module m
 
 // CHECK-LABEL: Testing : "_QMmPtest"
-// CHECK: func.region0#0 <-> func.region0#1: MayAlias
+// CHECK: func.region0#0 <-> func.region0#1: NoAlias
 
 func.func @_QMmPtest(%arg0: !fir.ref<!fir.type<_QMmTt{pointer_component:!fir.box<!fir.ptr<f32>>}>> {fir.bindc_name = "a"}, %arg1: !fir.ref<!fir.type<_QMmTt{pointer_component:!fir.box<!fir.ptr<f32>>}>> {fir.bindc_name = "b"}, %arg2: !fir.ref<f32> {fir.bindc_name = "x", fir.target}) attributes {test.ptr = "func"} {
   %0 = fir.field_index pointer_component, !fir.type<_QMmTt{pointer_component:!fir.box<!fir.ptr<f32>>}>
@@ -137,8 +137,7 @@ func.func private @_QPtest2(!fir.ref<f32>)
 // end module m
 
 // CHECK-LABEL: Testing : "_QMmPtest"
-// FIXME: MayAlias must be NoAlias
-// CHECK: func.region0#0 <-> func.region0#1: MayAlias
+// CHECK: func.region0#0 <-> func.region0#1: NoAlias
 
 func.func @_QMmPtest(%arg0: !fir.ref<!fir.type<_QMmTt{allocatable_component:!fir.box<!fir.heap<f32>>}>> {fir.bindc_name = "a"}, %arg1: !fir.ref<!fir.type<_QMmTt{allocatable_component:!fir.box<!fir.heap<f32>>}>> {fir.bindc_name = "b"}) attributes {test.ptr = "func"} {
   %0 = fir.field_index allocatable_component, !fir.type<_QMmTt{allocatable_component:!fir.box<!fir.heap<f32>>}>
diff --git a/flang/test/Analysis/AliasAnalysis/alias-analysis-9.fir b/flang/test/Analysis/AliasAnalysis/alias-analysis-9.fir
index df24a6d32aa59..67ea4d20caa60 100644
--- a/flang/test/Analysis/AliasAnalysis/alias-analysis-9.fir
+++ b/flang/test/Analysis/AliasAnalysis/alias-analysis-9.fir
@@ -17,13 +17,13 @@
 // end module
 
 // CHECK-LABEL: Testing : "_QMmPfoo"
-// TODO: x and y are non pointer, non target argument and therefore do not alias.
-// CHECK-DAG: x#0 <-> y#0: MayAlias
+// x and y are non pointer, non target argument and therefore do not alias.
+// CHECK-DAG: x#0 <-> y#0: NoAlias
 
-// TODO: y is not a pointer object and therefore does not alias with the x%next component. 
-//       Also assigning x to y would not modify x.next
-// CHECK-DAG: y#0 <-> xnext1#0: MayAlias
-// CHECK-DAG: y#0 <-> xnext2#0: MayAlias
+// y is not a pointer object and therefore does not alias with the x%next
+// component.  Also assigning x to y would not modify x.next
+// CHECK-DAG: y#0 <-> xnext1#0: NoAlias
+// CHECK-DAG: y#0 <-> xnext2#0: NoAlias
 
 // We need to catch the fact that assigning y to x will modify xnext. 
 // The only side-effect between the 2 loads of x.next is the assignment to x, 

>From 9f6d2a7add52dcd3fe51d7376be91b1f3e9b7646 Mon Sep 17 00:00:00 2001
From: "Joel E. Denny" <jdenny.ornl at gmail.com>
Date: Thu, 30 May 2024 15:09:54 -0400
Subject: [PATCH 2/2] WIP: Fix case of ptr dummy arg vs. ptr component

---
 .../lib/Optimizer/Analysis/AliasAnalysis.cpp  | 41 ++++++++++++++++++-
 .../AliasAnalysis/alias-analysis-3.fir        |  4 +-
 2 files changed, 41 insertions(+), 4 deletions(-)

diff --git a/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp b/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp
index 571b78dc64aa5..9d6640bf181ec 100644
--- a/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp
+++ b/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp
@@ -145,7 +145,7 @@ AliasResult AliasAnalysis::alias(Value lhs, Value rhs) {
         ((lhsSrc.approximateSource && !lhsSrc.isData() && !rhsSrc.approximateSource) ||
          (rhsSrc.approximateSource && !rhsSrc.isData() && !lhsSrc.approximateSource))) {
       LLVM_DEBUG(llvm::dbgs()
-                 << "  aliasing between composite and pointer component\n");
+                 << "  aliasing between composite and non-data component\n");
       return AliasResult::MayAlias;
     }
 
@@ -185,13 +185,50 @@ AliasResult AliasAnalysis::alias(Value lhs, Value rhs) {
     src2->attributes.set(Attribute::Target);
   }
 
-  // Dummy TARGET/POINTER argument may alias with a global TARGET/POINTER.
+  // Two TARGET/POINTERs may alias.
   if (src1->isTargetOrPointer() && src2->isTargetOrPointer() &&
       src1->isData() == src2->isData()) {
     LLVM_DEBUG(llvm::dbgs() << "  aliasing because of target or pointer\n");
     return AliasResult::MayAlias;
   }
 
+  // A pointer dummy arg may alias a global composite with a pointer component.
+  //
+  // module m
+  //   type t
+  //      real, pointer :: p
+  //   end type
+  //   type(t) :: a
+  //   type(t) :: b
+  // contains
+  //   subroutine test(p)
+  //     real, pointer :: p
+  //     p = 42
+  //     a = b
+  //     print *, p
+  //   end subroutine
+  // end module
+  // program
+  //   use m
+  //   real, target :: x1 = 1
+  //   real, target :: x2 = 2
+  //   a%p => x1
+  //   b%p => x2
+  //   call test(a%p)
+  // end
+  //
+  // The dummy argument p is an alias for a%p, even for the purposes of pointer
+  // association during the assignment a = b.  Thus, the program should print 2.
+  if (src1->kind == SourceKind::Global &&
+      src1->isRecordWithPointerComponent() &&
+      src2->kind == SourceKind::Argument &&
+      src2->attributes.test(Attribute::Pointer)) {
+    LLVM_DEBUG(llvm::dbgs()
+               << "  aliasing because of pointer arg and global composite with "
+               << "pointer component\n");
+    return AliasResult::MayAlias;
+  }
+
   return AliasResult::NoAlias;
 }
 
diff --git a/flang/test/Analysis/AliasAnalysis/alias-analysis-3.fir b/flang/test/Analysis/AliasAnalysis/alias-analysis-3.fir
index 2bf326f2d2af2..eab438576c2bc 100644
--- a/flang/test/Analysis/AliasAnalysis/alias-analysis-3.fir
+++ b/flang/test/Analysis/AliasAnalysis/alias-analysis-3.fir
@@ -16,9 +16,9 @@
 //   end subroutine test
 // end module m
 
-// A composite with a pointer component does not alias with a dummy pointer
+// A composite with a pointer component may alias with a dummy pointer
 // CHECK-LABEL: Testing : "_QMmPtest
-// CHECK: a#0 <-> func.region0#0: NoAlias
+// CHECK: a#0 <-> func.region0#0: MayAlias
 
 // a's box cannot alias with raw reference to f32 (x)
 // CHECK: a#0 <-> func.region0#1: NoAlias



More information about the flang-commits mailing list