[flang-commits] [flang] [flang] AliasAnalysis: Fix pointer component logic (PR #94242)
via flang-commits
flang-commits at lists.llvm.org
Thu Jun 13 13:53:25 PDT 2024
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-flang-fir-hlfir
Author: Joel E. Denny (jdenny-ornl)
<details>
<summary>Changes</summary>
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).
---
Patch is 23.63 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/94242.diff
4 Files Affected:
- (modified) flang/include/flang/Optimizer/Analysis/AliasAnalysis.h (+4-5)
- (modified) flang/lib/Optimizer/Analysis/AliasAnalysis.cpp (+91-17)
- (modified) flang/test/Analysis/AliasAnalysis/alias-analysis-3.fir (+7-8)
- (modified) flang/test/Analysis/AliasAnalysis/alias-analysis-9.fir (+192-7)
``````````diff
diff --git a/flang/include/flang/Optimizer/Analysis/AliasAnalysis.h b/flang/include/flang/Optimizer/Analysis/AliasAnalysis.h
index 8cb6e92e41d97..4963d39c52bdd 100644
--- a/flang/include/flang/Optimizer/Analysis/AliasAnalysis.h
+++ b/flang/include/flang/Optimizer/Analysis/AliasAnalysis.h
@@ -153,17 +153,16 @@ struct AliasAnalysis {
/// Return true, if Target or Pointer attribute is set.
bool isTargetOrPointer() const;
- /// Return true, if the memory source's `valueType` is a reference type
- /// to an object of derived type that contains a component with POINTER
- /// attribute.
- bool isRecordWithPointerComponent() const;
-
bool isDummyArgument() const;
bool isData() const;
bool isBoxData() const;
mlir::Type getType() const;
+ /// 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);
diff --git a/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp b/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp
index 2084962fde729..87389a848b9bf 100644
--- a/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp
+++ b/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp
@@ -60,6 +60,14 @@ void AliasAnalysis::Source::print(llvm::raw_ostream &os) const {
attributes.Dump(os, EnumToString);
}
+bool AliasAnalysis::Source::isRecordWithPointerComponent(mlir::Type ty) {
+ auto eleTy = fir::dyn_cast_ptrEleTy(ty);
+ if (!eleTy)
+ return false;
+ // TO DO: Look for pointer components
+ return mlir::isa<fir::RecordType>(eleTy);
+}
+
bool AliasAnalysis::Source::isPointerReference(mlir::Type ty) {
auto eleTy = fir::dyn_cast_ptrEleTy(ty);
if (!eleTy)
@@ -86,14 +94,6 @@ bool AliasAnalysis::Source::isBoxData() const {
origin.isData;
}
-bool AliasAnalysis::Source::isRecordWithPointerComponent() const {
- auto eleTy = fir::dyn_cast_ptrEleTy(valueType);
- if (!eleTy)
- return false;
- // TO DO: Look for pointer components
- return mlir::isa<fir::RecordType>(eleTy);
-}
-
AliasResult AliasAnalysis::alias(Value lhs, Value rhs) {
// TODO: alias() has to be aware of the function scopes.
// After MLIR inlining, the current implementation may
@@ -115,6 +115,10 @@ 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.
if (lhsSrc.origin == rhsSrc.origin) {
LLVM_DEBUG(llvm::dbgs()
<< " aliasing because same source kind and origin\n");
@@ -122,6 +126,34 @@ AliasResult AliasAnalysis::alias(Value lhs, Value rhs) {
return AliasResult::MayAlias;
return AliasResult::MustAlias;
}
+ // If one value is the address of a composite, and if the other value is the
+ // address of a pointer/allocatable component of that composite, their
+ // origins compare unequal because the latter has !isData(). As for the
+ // address of any component vs. the address of the composite, a store to one
+ // can affect a load from the other, so the result should be MayAlias. To
+ // catch this case, we conservatively return MayAlias when one value is the
+ // address of a composite, the other value is non-data, and they have the
+ // same origin value.
+ //
+ // TODO: That logic does not check that the latter is actually a component
+ // of the former, so it can return MayAlias when unnecessary. For example,
+ // they might both be addresses of components of a larger composite.
+ //
+ // FIXME: Actually, we should generalize from
+ // Source::isRecordWithPointerComponent to any composite because a component
+ // with !isData() is not always a pointer. However,
+ // Source::isRecordWithPointerComponent currently doesn't actually check for
+ // pointer components, so it's fine for now.
+ if (lhsSrc.origin.u == rhsSrc.origin.u &&
+ ((Source::isRecordWithPointerComponent(lhs.getType()) &&
+ !rhsSrc.isData()) ||
+ (Source::isRecordWithPointerComponent(rhs.getType()) &&
+ !lhsSrc.isData()))) {
+ LLVM_DEBUG(llvm::dbgs()
+ << " aliasing between composite and non-data component with "
+ << "same source kind and origin value\n");
+ return AliasResult::MayAlias;
+ }
// Two host associated accesses may overlap due to an equivalence.
if (lhsSrc.kind == SourceKind::HostAssoc) {
@@ -131,12 +163,17 @@ AliasResult AliasAnalysis::alias(Value lhs, Value rhs) {
}
Source *src1, *src2;
+ Value *val1, *val2;
if (lhsSrc.kind < rhsSrc.kind) {
src1 = &lhsSrc;
src2 = &rhsSrc;
+ val1 = &lhs;
+ val2 = &rhs;
} else {
src1 = &rhsSrc;
src2 = &lhsSrc;
+ val1 = &rhs;
+ val2 = &lhs;
}
if (src1->kind == SourceKind::Argument &&
@@ -159,21 +196,56 @@ 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;
}
- // 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");
+ // A pointer dummy arg (but not a pointer component of a dummy arg) may alias
+ // a pointer component and thus the associated composite. That composite
+ // might be a global or another dummy arg. This is an example of the global
+ // composite case:
+ //
+ // 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 ((Source::isRecordWithPointerComponent(val1->getType()) &&
+ src1->kind != SourceKind::Allocate &&
+ src2->kind == SourceKind::Argument &&
+ src2->attributes.test(Attribute::Pointer) && !src2->isData() &&
+ !Source::isRecordWithPointerComponent(src2->valueType)) ||
+ (Source::isRecordWithPointerComponent(val2->getType()) &&
+ src2->kind != SourceKind::Allocate &&
+ src1->kind == SourceKind::Argument &&
+ src1->attributes.test(Attribute::Pointer) && !src1->isData() &&
+ !Source::isRecordWithPointerComponent(src1->valueType))) {
+ LLVM_DEBUG(llvm::dbgs()
+ << " aliasing between pointer arg and composite with pointer "
+ << "component\n");
return AliasResult::MayAlias;
}
@@ -360,6 +432,8 @@ AliasAnalysis::Source AliasAnalysis::getSource(mlir::Value v,
defOp = v.getDefiningOp();
})
.Case<hlfir::DesignateOp>([&](auto op) {
+ auto varIf = llvm::cast<fir::FortranVariableOpInterface>(defOp);
+ attributes |= getAttrsFromVariable(varIf);
// Track further through the memory indexed into
// => if the source arrays/structures don't alias then nor do the
// results of hlfir.designate
diff --git a/flang/test/Analysis/AliasAnalysis/alias-analysis-3.fir b/flang/test/Analysis/AliasAnalysis/alias-analysis-3.fir
index 91829a461dc72..eab438576c2bc 100644
--- a/flang/test/Analysis/AliasAnalysis/alias-analysis-3.fir
+++ b/flang/test/Analysis/AliasAnalysis/alias-analysis-3.fir
@@ -20,8 +20,8 @@
// CHECK-LABEL: Testing : "_QMmPtest
// CHECK: a#0 <-> func.region0#0: MayAlias
-// 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..a5380bde9d108 100644
--- a/flang/test/Analysis/AliasAnalysis/alias-analysis-9.fir
+++ b/flang/test/Analysis/AliasAnalysis/alias-analysis-9.fir
@@ -1,5 +1,13 @@
-// RUN: fir-opt %s -pass-pipeline='builtin.module(func.func(test-fir-alias-analysis))' 2>&1 | FileCheck %s
+// RUN: fir-opt -debug %s -split-input-file \
+// RUN: -pass-pipeline='builtin.module(func.func(test-fir-alias-analysis))' \
+// RUN: 2>&1 | FileCheck -match-full-lines %s
+// FIXME: Extend much of this to check that it also works after
+// convert-hlfir-to-fir, where component access is via fir.coordinate_of instead
+// of hlfir.designate.
+
+// FIXME: What about renaming this test to ptr-component.fir? What about
+// merging with alias-analysis-3.fir as it has the same focus?
// module m
// type t
@@ -17,13 +25,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,
@@ -35,6 +43,12 @@
// we are currently not comparing operands involved in offset computations
// CHECK-DAG: xnext1#0 <-> xnext2#0: MayAlias
+// TODO: This should be NoAlias. However, AliasAnalysis currently
+// indiscriminately treats all pointers as aliasing. That makes sense for the
+// addresses within the pointers but not necessarily for the addresses of the
+// pointers.
+// CHECK-DAG: xnext1#0 <-> ynext#0: MayAlias
+
func.func @_QMmPfoo(%arg0: !fir.ref<!fir.type<_QMmTt{next:!fir.box<!fir.ptr<!fir.type<_QMmTt>>>,i:i32}>> {fir.bindc_name = "x"}, %arg1: !fir.ref<!fir.type<_QMmTt{next:!fir.box<!fir.ptr<!fir.type<_QMmTt>>>,i:i32}>> {fir.bindc_name = "y"}) {
%0 = fir.alloca i32 {bindc_name = "i1", uniq_name = "_QMmFfooEi1"}
%1:2 = hlfir.declare %0 {uniq_name = "_QMmFfooEi1"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
@@ -55,5 +69,176 @@ func.func @_QMmPfoo(%arg0: !fir.ref<!fir.type<_QMmTt{next:!fir.box<!fir.ptr<!fir
%14 = hlfir.designate %13{"i"} : (!fir.ptr<!fir.type<_QMmTt{next:!fir.box<!fir.ptr<!fir.type<_QMmTt>>>,i:i32}>>) -> !fir.ref<i32>
%15 = fir.load %14 : !fir.ref<i32>
hlfir.assign %15 to %3#0 : i32, !fir.ref<i32>
+ %16 = hlfir.designate %5#0{"next"} {fortran_attrs = #fir.var_attrs<pointer>, test.ptr = "ynext"} : (!fir.ref<!fir.type<_QMmTt{next:!fir.box<!fir.ptr<!fir.type<_QMmTt>>>,i:i32}>>) -> !fir.ref<!fir.box<!fir.ptr<!fir.type<_QMmTt{next:!fir.box<!fir.ptr<!fir.type<_QMmTt>>>,i:i32}>>>>
+ return
+}
+
+// -----
+
+// The address of a composite aliases the address of any component, including an
+// allocatable component. Like the address of a pointer, the address of an
+// allocatable is considered non-data, so AliasAnalysis has special handling to
+// detect the aliasing.
+
+// module m
+// type t
+// integer, allocatable :: p
+// end type
+// type(t) :: x
+// contains
+// subroutine test()
+// ! access x%p
+// end subroutine
+// end module
+
+// CHECK-LABEL: Testing : "_QMmPtest"
+// CHECK-DAG: x#0 <-> x%p#0: MayAlias
+
+func.func @_QMmPtest() {
+ %0 = fir.address_of(@_QMmEx) : !fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.heap<i32>>}>>
+ %1:2 = hlfir.declare %0 {test.ptr="x", uniq_name = "_QMmEx"} : (!fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.heap<i32>>}>>) -> (!fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.heap<i32>>}>>, !fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.heap<i32>>}>>)
+ %2 = hlfir.designate %1#0{"p"} {test.ptr="x%p", fortran_attrs = #fir.var_attrs<allocatable>} : (!fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.heap<i32>>}>>) -> !fir.ref<!fir.box<!fir.heap<i32>>>
+ return
+}
+
+// -----
+
+// Nested composites.
+
+// module m
+// type t1
+// integer, pointer :: p
+// end type
+// type t2
+// type(t1) :: x
+// integer, pointer :: p
+// integer :: i
+// end type
+// contains
+// subroutine test()
+// type(t2) :: x
+// end subroutine
+// end module
+
+// CHECK-LABEL: Testing : "_QMmPtest"
+
+// The addresses of a composite and its pointer component alias even if the
+// composite is nested within another composite.
+// CHECK-DAG: x#0 <-> x%p#0: MayAlias
+// CHECK-DAG: x%x#0 <-> x%x%p#0: MayAlias
+
+// The addresses of different components of the same composite do not alias.
+//
+// TODO: Thus, all results below should be NoAlias. However, AliasAnalysis
+// normally does not recognize when two values (x%x vs. x%i) are distinct
+// components of the same composite (x) as opposed to being potentially
+// overlapping parts of something, so it returns MayAlias. There is special
+// handling for a pointer component (x%p) that does recognize it as separate
+// from other components (x%i). But it does not yet distinguish the composite
+// (x) from a component (x%x) that is also a composite with a pointer component
+// (x%x%p). Thus, because x and x%p can alias, it assumes x%x and x%p can too.
+// CHECK-DAG: x%x#0 <-> x%i#0: MayAlias
+// CHECK-DAG: x%p#0 <-> x%i#0: NoAlias
+// CHECK-DAG: x%x#0 <-> x%p#0: MayAlias
+
+func.func @_QMmPtest() {
+ %0 = fir.alloca !fir.type<_QMmTt2{x:!fir.type<_QMmTt1{p:!fir.box<!fir.ptr<i32>>}>,p:!fir.box<!fir.ptr<i32>>,i:i32}> {bindc_name = "x", uniq_name = "_QMmFtestEx"}
+ %1:2 = hlfir.declare %0 {test.ptr="x", uniq_name = "_QMmFtestEx"} : (!fir.ref<!fir.type<_QMmTt2{x:!fir.type<_QMmTt1{p:!fir.box<!fir.ptr<i32>>}>,p:!fir.box<!fir.ptr<i32>>,i:i32}>>) -> (!fir.ref<!fir.type<_QMmTt2{x:!fir.type<_QMmTt1{p:!fir.box<!fir.ptr<i32>>}>,p:!fir.box<!fir.ptr<i32>>,i:i32}>>, !fir.ref<!fir.type<_QMmTt2{x:!fir.type<_QMmTt1{p:!fir.box<!fir.ptr<i32>>}>,p:!fir.box<!fir.ptr<i32>>,i:i32}>>)
+ %2 = hlfir.designate %1#0{"x"} {test.ptr="x%x"} : (!fir.ref<!fir.type<_QMmTt2{x:!fir.type<_QMmTt1{p:!fir.box<!fir.ptr<i32>>}>,p:!fir.box<!fir.ptr<i32>>,i:i32}>>) -> !fir.ref<!fir.type<_QMmTt1{p:!fir.box<!fir.ptr<i32>>}>>
+ %3 = hlfir.designate %1#0{"p"} {test.ptr="x%p", fortran_attrs = #fir.var_attrs<pointer>} : (!fir.ref<!fir.type<_QMmTt2{x:!fir.type<_QMmTt1{p:!fir.box<!fir.ptr<i32>>}>,p:!fir.box<!fir.ptr<i32>>,i:i32}>>) -> !fir.ref<!fir.box<!fir.ptr<i32>>>
+ %4 = hlfir.designate %1#0{"i"} {test.ptr="x%i"} : (!fir.ref<!fir.type<_QMmTt2{x:!fir.type<_QMmTt1{p:!fir.box<!fir.ptr<i32>>}>,p:!fir.box<!fir.ptr<i32>>,i:i32}>>) -> !fir.ref<i32>
+ %5 = hlfir.designate %2{"p"} {test.ptr="x%x%p", fortran_attrs = #fir.var_attrs<pointer>} : (!fir.ref<!fir.type<_QMmTt1{p:!fir.box<!fir.ptr<i32>>}>>) -> !fir.ref<!fir.box<!fir.ptr<i32>>>
+ return
+}
+
+// -----
+
+// Pointer that might dynamically be a component.
+
+// The address of a pointer dummy arg (argp) might alias the address of a
+// pointer component (x%p) and thus the address of the associated composite (x),
+// but it does not alias the addresses of other components (x%i) of the
+// composite. Moreover, the address *in* argp does not alias any of those.
+// Finally, an allocatable dummy arg (arga) should not be mistaken for a pointer
+// dummy arg and cannot have such aliasing.
+
+// module m
+// type t
+// integer, pointer :: p
+// integer i
+// end type
+// type(t) :: glob
+// contains
+// subroutine test(argp, arga, arg)
+// integer, pointer :: argp
+// integer, allocatable :: arga
+// type(t) :: arg
+// type(t) :: loc
+// end subroutine
+// end module
+
+// CHECK-LABEL: Testing : "_QMmPtest"
+
+// Check when composite is a dummy arg.
+// CHECK-DAG: argp#0 <-> arg#0: MayAlias
+// CHECK-DAG: argp#0 <-> arg%p#0: MayAlias
+// CHECK-DAG: argp#0 <-> arg%i#0: NoAlias
+// CHECK-DAG: argp.tgt#0 <-> arg#0: NoAlias
+// CHECK-DAG: argp.tgt#0 <-> arg%p#0: NoAlias
+// CHECK-DAG: argp.tgt#0 <-> arg%i#0: NoAlias
+// CHECK-DAG: arga#0 <-> arg#0: NoAlias
+// CHECK-DAG: arga#0 <-> arg%p#0: NoAlias
+
+// Check when composite is a global.
+// CHECK-DAG: argp#0 <-> glob#0: MayAlias
+// CHECK-DAG: argp#0 <-> glob%p#0: MayAlias
+// CHECK-DAG: argp#0 <-> glob%i#0: NoAlias
+// CHECK-DAG: argp.tgt#0 <-> glob#0: NoAlias
+// CHECK-DAG: argp.tgt#0 <-> glob%p#0: NoAlias
+// CHECK-DAG: argp.tgt#0 <-> glob%i#0: NoAlias
+// CHECK-DAG: arga#0 <-> glob#0: NoAlias
+// CHECK-DAG: arga#0 <-> glob%p#0: NoAlias
+
+// Check when composite is a local and thus cannot alias a dummy arg.
+//
+// TODO: The argp vs. loc%p cas...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/94242
More information about the flang-commits
mailing list