[flang-commits] [flang] 7323533 - [flang] AliasAnalysis: Fix pointer component logic (#94242)
via flang-commits
flang-commits at lists.llvm.org
Tue Oct 15 07:07:23 PDT 2024
Author: Joel E. Denny
Date: 2024-10-15T10:07:17-04:00
New Revision: 732353303e423237b7d23695a0e516728e491da4
URL: https://github.com/llvm/llvm-project/commit/732353303e423237b7d23695a0e516728e491da4
DIFF: https://github.com/llvm/llvm-project/commit/732353303e423237b7d23695a0e516728e491da4.diff
LOG: [flang] AliasAnalysis: Fix pointer component logic (#94242)
This PR applies the changes discussed in [[RFC] Rationale for Flang
AliasAnalysis pointer component
logic](https://discourse.llvm.org/t/rfc-rationale-for-flang-aliasanalysis-pointer-component-logic/79252).
In summary, this PR replaces the existing pointer component logic in
Flang's AliasAnalysis implementation. That logic focuses on aliasing
between pointers and non-pointer, non-target composites that have
pointer components. However, it is more conservative than necessary, and
some existing tests expect its current results when less conservative
results seem reasonable.
This PR splits the logic into two cases:
1. Source values are the same: Return MayAlias when one value is the
address of a composite, and the other value is statically the address of
a pointer component of that composite.
2. Source values are different: Return MayAlias when one value is the
address of a composite (actual argument), and the other value is the
address of a pointer (dummy arg) that might dynamically be a component
of that composite.
In both cases, the actual implementation is still more conservative than
described above, but it can be improved further later. Details appear in
the comments.
Additionally, this PR revises the logic that reports MayAlias for a
pointer/target vs. another pointer/target. It constrains the existing
logic to handle only isData cases, and it adds less conservative
handling of !isData cases elsewhere. First, it extends case 2 listed
above to cover the case where the actual argument is the address of a
pointer rather than a composite. Second, it adds a third case: where
target attributes enable aliasing with a dummy argument.
Added:
Modified:
flang/include/flang/Optimizer/Analysis/AliasAnalysis.h
flang/lib/Optimizer/Analysis/AliasAnalysis.cpp
flang/test/Analysis/AliasAnalysis/alias-analysis-3.fir
flang/test/Analysis/AliasAnalysis/ptr-component.fir
Removed:
################################################################################
diff --git a/flang/include/flang/Optimizer/Analysis/AliasAnalysis.h b/flang/include/flang/Optimizer/Analysis/AliasAnalysis.h
index 8ab5150cd7c812..97c64dc3419524 100644
--- a/flang/include/flang/Optimizer/Analysis/AliasAnalysis.h
+++ b/flang/include/flang/Optimizer/Analysis/AliasAnalysis.h
@@ -157,6 +157,26 @@ struct AliasAnalysis {
bool isData() const;
bool isBoxData() const;
+ /// @name Dummy Argument Aliasing
+ ///
+ /// Check conditions related to dummy argument aliasing.
+ ///
+ /// For all uses, a result of false can prevent MayAlias from being
+ /// reported, so the list of cases where false is returned is conservative.
+
+ ///@{
+ /// The address of a (possibly host associated) dummy argument of the
+ /// current function?
+ bool mayBeDummyArgOrHostAssoc() const;
+ /// \c mayBeDummyArgOrHostAssoc and the address of a pointer?
+ bool mayBePtrDummyArgOrHostAssoc() const;
+ /// The address of an actual argument of the current function?
+ bool mayBeActualArg() const;
+ /// \c mayBeActualArg and the address of either a pointer or a composite
+ /// with a pointer component?
+ bool mayBeActualArgWithPtr(const mlir::Value *val) const;
+ ///@}
+
mlir::Type getType() const;
};
diff --git a/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp b/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp
index 969dc748e7c540..8b7918744017cc 100644
--- a/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp
+++ b/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp
@@ -96,6 +96,39 @@ bool AliasAnalysis::Source::isBoxData() const {
origin.isData;
}
+bool AliasAnalysis::Source::mayBeDummyArgOrHostAssoc() const {
+ return kind != SourceKind::Allocate && kind != SourceKind::Global;
+}
+
+bool AliasAnalysis::Source::mayBePtrDummyArgOrHostAssoc() const {
+ // Must alias like dummy arg (or HostAssoc).
+ if (!mayBeDummyArgOrHostAssoc())
+ return false;
+ // Must be address of the dummy arg not of a dummy arg component.
+ if (isRecordWithPointerComponent(valueType))
+ return false;
+ // Must be address *of* (not *in*) a pointer.
+ return attributes.test(Attribute::Pointer) && !isData();
+}
+
+bool AliasAnalysis::Source::mayBeActualArg() const {
+ return kind != SourceKind::Allocate;
+}
+
+bool AliasAnalysis::Source::mayBeActualArgWithPtr(
+ const mlir::Value *val) const {
+ // Must not be local.
+ if (!mayBeActualArg())
+ return false;
+ // Can be address *of* (not *in*) a pointer.
+ if (attributes.test(Attribute::Pointer) && !isData())
+ return true;
+ // Can be address of a composite with a pointer component.
+ if (isRecordWithPointerComponent(val->getType()))
+ return true;
+ return false;
+}
+
AliasResult AliasAnalysis::alias(mlir::Value lhs, mlir::Value rhs) {
// TODO: alias() has to be aware of the function scopes.
// After MLIR inlining, the current implementation may
@@ -118,6 +151,10 @@ AliasResult AliasAnalysis::alias(mlir::Value lhs, mlir::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");
@@ -125,6 +162,31 @@ AliasResult AliasAnalysis::alias(mlir::Value lhs, mlir::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 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 &&
+ ((isRecordWithPointerComponent(lhs.getType()) && !rhsSrc.isData()) ||
+ (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) {
@@ -134,12 +196,17 @@ AliasResult AliasAnalysis::alias(mlir::Value lhs, mlir::Value rhs) {
}
Source *src1, *src2;
+ mlir::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 &&
@@ -162,23 +229,88 @@ AliasResult AliasAnalysis::alias(mlir::Value lhs, mlir::Value rhs) {
src2->attributes.set(Attribute::Target);
}
- // Dummy TARGET/POINTER argument may alias with a global TARGET/POINTER.
+ // Two TARGET/POINTERs may alias. The logic here focuses on data. Handling
+ // of non-data is included below.
if (src1->isTargetOrPointer() && src2->isTargetOrPointer() &&
- src1->isData() == src2->isData()) {
+ 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 ((isRecordWithPointerComponent(src1->valueType) &&
- src2->isTargetOrPointer()) ||
- (isRecordWithPointerComponent(src2->valueType) &&
- src1->isTargetOrPointer()) ||
- (isRecordWithPointerComponent(src1->valueType) &&
- isRecordWithPointerComponent(src2->valueType))) {
- LLVM_DEBUG(llvm::dbgs() << " aliasing because of pointer components\n");
+ // Aliasing for dummy arg with target attribute.
+ //
+ // The address of a dummy arg (or HostAssoc) may alias the address of a
+ // non-local (global or another dummy arg) when both have target attributes.
+ // If either is a composite, addresses of components may alias as well.
+ //
+ // The previous "if" calling isTargetOrPointer casts a very wide net and so
+ // reports MayAlias for many such cases that would otherwise be reported here.
+ // It specifically skips such cases where one or both values have !isData()
+ // (e.g., address *of* pointer/allocatable component vs. address of
+ // composite), so this "if" catches those cases.
+ if (src1->attributes.test(Attribute::Target) &&
+ src2->attributes.test(Attribute::Target) &&
+ ((src1->mayBeDummyArgOrHostAssoc() && src2->mayBeActualArg()) ||
+ (src2->mayBeDummyArgOrHostAssoc() && src1->mayBeActualArg()))) {
+ LLVM_DEBUG(llvm::dbgs()
+ << " aliasing between targets where one is a dummy arg\n");
+ return AliasResult::MayAlias;
+ }
+
+ // Aliasing for dummy arg that is a pointer.
+ //
+ // The address of a pointer dummy arg (but not a pointer component of a dummy
+ // arg) may alias the address of either (1) a non-local pointer or (2) thus a
+ // non-local composite with a pointer component. A non-local might be a
+ // global or another dummy arg. The following 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 main
+ // 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.
+ //
+ // The same is true when p is HostAssoc. For example, we might replace the
+ // test subroutine above with:
+ //
+ // subroutine test(p)
+ // real, pointer :: p
+ // call internal()
+ // contains
+ // subroutine internal()
+ // p = 42
+ // a = b
+ // print *, p
+ // end subroutine
+ // end subroutine
+ if ((src1->mayBePtrDummyArgOrHostAssoc() &&
+ src2->mayBeActualArgWithPtr(val2)) ||
+ (src2->mayBePtrDummyArgOrHostAssoc() &&
+ src1->mayBeActualArgWithPtr(val1))) {
+ LLVM_DEBUG(llvm::dbgs()
+ << " aliasing between pointer dummy arg and either pointer or "
+ << "composite with pointer component\n");
return AliasResult::MayAlias;
}
@@ -278,6 +410,8 @@ AliasAnalysis::Source AliasAnalysis::getSource(mlir::Value v,
followBoxData = true;
})
.Case<fir::ArrayCoorOp, fir::CoordinateOp>([&](auto op) {
+ if (isPointerReference(ty))
+ attributes.set(Attribute::Pointer);
v = op->getOperand(0);
defOp = v.getDefiningOp();
if (mlir::isa<fir::BaseBoxType>(v.getType()))
@@ -396,6 +530,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 91829a461dc72a..eab438576c2bcf 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/ptr-component.fir b/flang/test/Analysis/AliasAnalysis/ptr-component.fir
index ae53113f15d338..279143a5814606 100644
--- a/flang/test/Analysis/AliasAnalysis/ptr-component.fir
+++ b/flang/test/Analysis/AliasAnalysis/ptr-component.fir
@@ -1,6 +1,13 @@
-// RUN: fir-opt %s -pass-pipeline='builtin.module(func.func(test-fir-alias-analysis))' -split-input-file 2>&1 | FileCheck %s
+// Check AliasAnalysis for pointer components.
+//
+// Throughout this test, The ".fir" suffix on symbols indicates a version of the
+// MLIR after convert-hlfir-to-fir. A key
diff erence 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 t
@@ -18,23 +25,32 @@
// 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
+// CHECK-DAG: x.fir#0 <-> y.fir#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
+// CHECK-DAG: y.fir#0 <-> xnext1.fir#0: NoAlias
+// CHECK-DAG: y.fir#0 <-> xnext2.fir#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,
// therefore x needs to alias with x.next to prevent the loads from being merged.
// CHECK-DAG: x#0 <-> xnext1#0: MayAlias
// CHECK-DAG: x#0 <-> xnext2#0: MayAlias
+// CHECK-DAG: x.fir#0 <-> xnext1.fir#0: MayAlias
+// CHECK-DAG: x.fir#0 <-> xnext2.fir#0: MayAlias
// TODO: xnext1#0 <-> xnext2#0 are the same and therefore MustAlias but
// we are currently not comparing operands involved in offset computations
// CHECK-DAG: xnext1#0 <-> xnext2#0: MayAlias
+// CHECK-DAG: xnext1.fir#0 <-> xnext2.fir#0: MayAlias
+
+// CHECK-DAG: xnext1#0 <-> ynext#0: NoAlias
+// CHECK-DAG: xnext1.fir#0 <-> ynext.fir#0: NoAlias
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"}
@@ -56,6 +72,46 @@ 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
+}
+
+func.func @_QMmPfoo.fir(%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 !fir.box<!fir.type<_QMmTt{next:!fir.box<!fir.ptr<!fir.type<_QMmTt>>>,i:i32}>>
+ %1 = fir.alloca i32 {bindc_name = "i1", uniq_name = "_QMmFfooEi1"}
+ %2 = fir.declare %1 {uniq_name = "_QMmFfooEi1"} : (!fir.ref<i32>) -> !fir.ref<i32>
+ %3 = fir.alloca i32 {bindc_name = "i2", uniq_name = "_QMmFfooEi2"}
+ %4 = fir.declare %3 {uniq_name = "_QMmFfooEi2"} : (!fir.ref<i32>) -> !fir.ref<i32>
+ %5 = fir.declare %arg0 {test.ptr = "x.fir", uniq_name = "_QMmFfooEx"} : (!fir.ref<!fir.type<_QMmTt{next:!fir.box<!fir.ptr<!fir.type<_QMmTt>>>,i:i32}>>) -> !fir.ref<!fir.type<_QMmTt{next:!fir.box<!fir.ptr<!fir.type<_QMmTt>>>,i:i32}>>
+ %6 = fir.declare %arg1 {test.ptr = "y.fir", uniq_name = "_QMmFfooEy"} : (!fir.ref<!fir.type<_QMmTt{next:!fir.box<!fir.ptr<!fir.type<_QMmTt>>>,i:i32}>>) -> !fir.ref<!fir.type<_QMmTt{next:!fir.box<!fir.ptr<!fir.type<_QMmTt>>>,i:i32}>>
+ %7 = fir.field_index next, !fir.type<_QMmTt{next:!fir.box<!fir.ptr<!fir.type<_QMmTt>>>,i:i32}>
+ %8 = fir.coordinate_of %5, %7 {test.ptr="xnext1.fir"} : (!fir.ref<!fir.type<_QMmTt{next:!fir.box<!fir.ptr<!fir.type<_QMmTt>>>,i:i32}>>, !fir.field) -> !fir.ref<!fir.box<!fir.ptr<!fir.type<_QMmTt{next:!fir.box<!fir.ptr<!fir.type<_QMmTt>>>,i:i32}>>>>
+ %9 = fir.load %8 : !fir.ref<!fir.box<!fir.ptr<!fir.type<_QMmTt{next:!fir.box<!fir.ptr<!fir.type<_QMmTt>>>,i:i32}>>>>
+ %10 = fir.box_addr %9 : (!fir.box<!fir.ptr<!fir.type<_QMmTt{next:!fir.box<!fir.ptr<!fir.type<_QMmTt>>>,i:i32}>>>) -> !fir.ptr<!fir.type<_QMmTt{next:!fir.box<!fir.ptr<!fir.type<_QMmTt>>>,i:i32}>>
+ %11 = fir.field_index i, !fir.type<_QMmTt{next:!fir.box<!fir.ptr<!fir.type<_QMmTt>>>,i:i32}>
+ %12 = fir.coordinate_of %10, %11 : (!fir.ptr<!fir.type<_QMmTt{next:!fir.box<!fir.ptr<!fir.type<_QMmTt>>>,i:i32}>>, !fir.field) -> !fir.ref<i32>
+ %13 = fir.load %12 : !fir.ref<i32>
+ fir.store %13 to %2 : !fir.ref<i32>
+ %14 = fir.embox %5 : (!fir.ref<!fir.type<_QMmTt{next:!fir.box<!fir.ptr<!fir.type<_QMmTt>>>,i:i32}>>) -> !fir.box<!fir.type<_QMmTt{next:!fir.box<!fir.ptr<!fir.type<_QMmTt>>>,i:i32}>>
+ %15 = fir.embox %6 : (!fir.ref<!fir.type<_QMmTt{next:!fir.box<!fir.ptr<!fir.type<_QMmTt>>>,i:i32}>>) -> !fir.box<!fir.type<_QMmTt{next:!fir.box<!fir.ptr<!fir.type<_QMmTt>>>,i:i32}>>
+ fir.store %14 to %0 : !fir.ref<!fir.box<!fir.type<_QMmTt{next:!fir.box<!fir.ptr<!fir.type<_QMmTt>>>,i:i32}>>>
+ %16 = fir.address_of(@_QQclX746D70332E66697200) : !fir.ref<!fir.char<1,9>>
+ %c9 = arith.constant 9 : index
+ %c14_i32 = arith.constant 14 : i32
+ %17 = fir.convert %0 : (!fir.ref<!fir.box<!fir.type<_QMmTt{next:!fir.box<!fir.ptr<!fir.type<_QMmTt>>>,i:i32}>>>) -> !fir.ref<!fir.box<none>>
+ %18 = fir.convert %15 : (!fir.box<!fir.type<_QMmTt{next:!fir.box<!fir.ptr<!fir.type<_QMmTt>>>,i:i32}>>) -> !fir.box<none>
+ %19 = fir.convert %16 : (!fir.ref<!fir.char<1,9>>) -> !fir.ref<i8>
+ %20 = fir.call @_FortranAAssign(%17, %18, %19, %c14_i32) : (!fir.ref<!fir.box<none>>, !fir.box<none>, !fir.ref<i8>, i32) -> none
+ %21 = fir.field_index next, !fir.type<_QMmTt{next:!fir.box<!fir.ptr<!fir.type<_QMmTt>>>,i:i32}>
+ %22 = fir.coordinate_of %5, %21 {test.ptr="xnext2.fir"}: (!fir.ref<!fir.type<_QMmTt{next:!fir.box<!fir.ptr<!fir.type<_QMmTt>>>,i:i32}>>, !fir.field) -> !fir.ref<!fir.box<!fir.ptr<!fir.type<_QMmTt{next:!fir.box<!fir.ptr<!fir.type<_QMmTt>>>,i:i32}>>>>
+ %23 = fir.load %22 : !fir.ref<!fir.box<!fir.ptr<!fir.type<_QMmTt{next:!fir.box<!fir.ptr<!fir.type<_QMmTt>>>,i:i32}>>>>
+ %24 = fir.box_addr %23 : (!fir.box<!fir.ptr<!fir.type<_QMmTt{next:!fir.box<!fir.ptr<!fir.type<_QMmTt>>>,i:i32}>>>) -> !fir.ptr<!fir.type<_QMmTt{next:!fir.box<!fir.ptr<!fir.type<_QMmTt>>>,i:i32}>>
+ %25 = fir.field_index i, !fir.type<_QMmTt{next:!fir.box<!fir.ptr<!fir.type<_QMmTt>>>,i:i32}>
+ %26 = fir.coordinate_of %24, %25 : (!fir.ptr<!fir.type<_QMmTt{next:!fir.box<!fir.ptr<!fir.type<_QMmTt>>>,i:i32}>>, !fir.field) -> !fir.ref<i32>
+ %27 = fir.load %26 : !fir.ref<i32>
+ fir.store %27 to %4 : !fir.ref<i32>
+ %28 = fir.field_index next, !fir.type<_QMmTt{next:!fir.box<!fir.ptr<!fir.type<_QMmTt>>>,i:i32}>
+ %29 = fir.coordinate_of %6, %28 {test.ptr="ynext.fir"} : (!fir.ref<!fir.type<_QMmTt{next:!fir.box<!fir.ptr<!fir.type<_QMmTt>>>,i:i32}>>, !fir.field) -> !fir.ref<!fir.box<!fir.ptr<!fir.type<_QMmTt{next:!fir.box<!fir.ptr<!fir.type<_QMmTt>>>,i:i32}>>>>
return
}
@@ -64,6 +120,7 @@ func.func @_QMmPfoo(%arg0: !fir.ref<!fir.type<_QMmTt{next:!fir.box<!fir.ptr<!fir
// Same test as above focusing on aliasing between x%next and y%next data
// CHECK-LABEL: Testing : "_QMmPfoo2"
// CHECK-DAG: xnext#0 <-> ynext#0: MayAlias
+// CHECK-DAG: xnext.fir#0 <-> ynext.fir#0: MayAlias
func.func @_QMmPfoo2(%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"}) {
%4:2 = hlfir.declare %arg0 {uniq_name = "_QMmFfooEx"} : (!fir.ref<!fir.type<_QMmTt{next:!fir.box<!fir.ptr<!fir.type<_QMmTt>>>,i:i32}>>) -> (!fir.ref<!fir.type<_QMmTt{next:!fir.box<!fir.ptr<!fir.type<_QMmTt>>>,i:i32}>>, !fir.ref<!fir.type<_QMmTt{next:!fir.box<!fir.ptr<!fir.type<_QMmTt>>>,i:i32}>>)
@@ -78,6 +135,20 @@ func.func @_QMmPfoo2(%arg0: !fir.ref<!fir.type<_QMmTt{next:!fir.box<!fir.ptr<!fi
return
}
+func.func @_QMmPfoo2.fir(%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.declare %arg0 {uniq_name = "_QMmFfooEx"} : (!fir.ref<!fir.type<_QMmTt{next:!fir.box<!fir.ptr<!fir.type<_QMmTt>>>,i:i32}>>) -> !fir.ref<!fir.type<_QMmTt{next:!fir.box<!fir.ptr<!fir.type<_QMmTt>>>,i:i32}>>
+ %1 = fir.declare %arg1 {uniq_name = "_QMmFfooEy"} : (!fir.ref<!fir.type<_QMmTt{next:!fir.box<!fir.ptr<!fir.type<_QMmTt>>>,i:i32}>>) -> !fir.ref<!fir.type<_QMmTt{next:!fir.box<!fir.ptr<!fir.type<_QMmTt>>>,i:i32}>>
+ %2 = fir.field_index next, !fir.type<_QMmTt{next:!fir.box<!fir.ptr<!fir.type<_QMmTt>>>,i:i32}>
+ %3 = fir.coordinate_of %0, %2 : (!fir.ref<!fir.type<_QMmTt{next:!fir.box<!fir.ptr<!fir.type<_QMmTt>>>,i:i32}>>, !fir.field) -> !fir.ref<!fir.box<!fir.ptr<!fir.type<_QMmTt{next:!fir.box<!fir.ptr<!fir.type<_QMmTt>>>,i:i32}>>>>
+ %4 = fir.load %3 : !fir.ref<!fir.box<!fir.ptr<!fir.type<_QMmTt{next:!fir.box<!fir.ptr<!fir.type<_QMmTt>>>,i:i32}>>>>
+ %5 = fir.box_addr %4 {test.ptr = "xnext.fir"} : (!fir.box<!fir.ptr<!fir.type<_QMmTt{next:!fir.box<!fir.ptr<!fir.type<_QMmTt>>>,i:i32}>>>) -> !fir.ptr<!fir.type<_QMmTt{next:!fir.box<!fir.ptr<!fir.type<_QMmTt>>>,i:i32}>>
+ %6 = fir.field_index next, !fir.type<_QMmTt{next:!fir.box<!fir.ptr<!fir.type<_QMmTt>>>,i:i32}>
+ %7 = fir.coordinate_of %1, %6 : (!fir.ref<!fir.type<_QMmTt{next:!fir.box<!fir.ptr<!fir.type<_QMmTt>>>,i:i32}>>, !fir.field) -> !fir.ref<!fir.box<!fir.ptr<!fir.type<_QMmTt{next:!fir.box<!fir.ptr<!fir.type<_QMmTt>>>,i:i32}>>>>
+ %8 = fir.load %7 : !fir.ref<!fir.box<!fir.ptr<!fir.type<_QMmTt{next:!fir.box<!fir.ptr<!fir.type<_QMmTt>>>,i:i32}>>>>
+ %9 = fir.box_addr %8 {test.ptr = "ynext.fir"} : (!fir.box<!fir.ptr<!fir.type<_QMmTt{next:!fir.box<!fir.ptr<!fir.type<_QMmTt>>>,i:i32}>>>) -> !fir.ptr<!fir.type<_QMmTt{next:!fir.box<!fir.ptr<!fir.type<_QMmTt>>>,i:i32}>>
+ return
+}
+
// -----
// module m
@@ -93,6 +164,7 @@ func.func @_QMmPfoo2(%arg0: !fir.ref<!fir.type<_QMmTt{next:!fir.box<!fir.ptr<!fi
// CHECK-LABEL: Testing : "_QMmPfoo3"
// CHECK-DAG: yarray#0 <-> xarray#0: MayAlias
+// CHECK-DAG: yarray.fir#0 <-> xarray.fir#0: MayAlias
func.func @_QMmPfoo3(%arg0: !fir.ref<!fir.type<_QMmTta{array:!fir.box<!fir.ptr<!fir.array<?xi32>>>}>> {fir.bindc_name = "x"}, %arg1: !fir.ref<!fir.type<_QMmTta{array:!fir.box<!fir.ptr<!fir.array<?xi32>>>}>> {fir.bindc_name = "y"}) {
%0:2 = hlfir.declare %arg0 {uniq_name = "_QMmFfooEx"} : (!fir.ref<!fir.type<_QMmTta{array:!fir.box<!fir.ptr<!fir.array<?xi32>>>}>>) -> (!fir.ref<!fir.type<_QMmTta{array:!fir.box<!fir.ptr<!fir.array<?xi32>>>}>>, !fir.ref<!fir.type<_QMmTta{array:!fir.box<!fir.ptr<!fir.array<?xi32>>>}>>)
@@ -109,3 +181,659 @@ func.func @_QMmPfoo3(%arg0: !fir.ref<!fir.type<_QMmTta{array:!fir.box<!fir.ptr<!
hlfir.assign %5 to %8 : i32, !fir.ref<i32>
return
}
+
+func.func @_QMmPfoo3.fir(%arg0: !fir.ref<!fir.type<_QMmTta{array:!fir.box<!fir.ptr<!fir.array<?xi32>>>}>> {fir.bindc_name = "x"}, %arg1: !fir.ref<!fir.type<_QMmTta{array:!fir.box<!fir.ptr<!fir.array<?xi32>>>}>> {fir.bindc_name = "y"}) {
+ %0 = fir.declare %arg0 {uniq_name = "_QMmFfooEx"} : (!fir.ref<!fir.type<_QMmTta{array:!fir.box<!fir.ptr<!fir.array<?xi32>>>}>>) -> !fir.ref<!fir.type<_QMmTta{array:!fir.box<!fir.ptr<!fir.array<?xi32>>>}>>
+ %1 = fir.declare %arg1 {uniq_name = "_QMmFfooEy"} : (!fir.ref<!fir.type<_QMmTta{array:!fir.box<!fir.ptr<!fir.array<?xi32>>>}>>) -> !fir.ref<!fir.type<_QMmTta{array:!fir.box<!fir.ptr<!fir.array<?xi32>>>}>>
+ %2 = fir.field_index array, !fir.type<_QMmTta{array:!fir.box<!fir.ptr<!fir.array<?xi32>>>}>
+ %3 = fir.coordinate_of %1, %2 : (!fir.ref<!fir.type<_QMmTta{array:!fir.box<!fir.ptr<!fir.array<?xi32>>>}>>, !fir.field) -> !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>
+ %4 = fir.load %3 : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>
+ %c1 = arith.constant 1 : index
+ %c0 = arith.constant 0 : index
+ %5:3 = fir.box_dims %4, %c0 : (!fir.box<!fir.ptr<!fir.array<?xi32>>>, index) -> (index, index, index)
+ %6 = fir.shift %5#0 : (index) -> !fir.shift<1>
+ %7 = fir.array_coor %4(%6) %c1 {test.ptr="yarray.fir"} : (!fir.box<!fir.ptr<!fir.array<?xi32>>>, !fir.shift<1>, index) -> !fir.ref<i32>
+ %8 = fir.load %7 : !fir.ref<i32>
+ %9 = fir.field_index array, !fir.type<_QMmTta{array:!fir.box<!fir.ptr<!fir.array<?xi32>>>}>
+ %10 = fir.coordinate_of %0, %9 : (!fir.ref<!fir.type<_QMmTta{array:!fir.box<!fir.ptr<!fir.array<?xi32>>>}>>, !fir.field) -> !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>
+ %11 = fir.load %10 : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>
+ %c1_0 = arith.constant 1 : index
+ %c0_1 = arith.constant 0 : index
+ %12:3 = fir.box_dims %11, %c0_1 : (!fir.box<!fir.ptr<!fir.array<?xi32>>>, index) -> (index, index, index)
+ %13 = fir.shift %12#0 : (index) -> !fir.shift<1>
+ %14 = fir.array_coor %11(%13) %c1_0 {test.ptr="xarray.fir"} : (!fir.box<!fir.ptr<!fir.array<?xi32>>>, !fir.shift<1>, index) -> !fir.ref<i32>
+ fir.store %8 to %14 : !fir.ref<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
+// CHECK-DAG: x.fir#0 <-> x%p.fir#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
+}
+
+func.func @_QMmPtest.fir() {
+ %0 = fir.address_of(@_QMmEx) : !fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.heap<i32>>}>>
+ %1 = fir.declare %0 {test.ptr = "x.fir", 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>>}>>
+ %2 = fir.field_index p, !fir.type<_QMmTt{p:!fir.box<!fir.heap<i32>>}>
+ %3 = fir.coordinate_of %1, %2 {test.ptr="x%p.fir"} : (!fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.heap<i32>>}>>, !fir.field) -> !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
+// CHECK-DAG: x.fir#0 <-> x%p.fir#0: MayAlias
+// CHECK-DAG: x%x.fir#0 <-> x%x%p.fir#0: MayAlias
+
+// The addresses of
diff erent 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
+// CHECK-DAG: x%x.fir#0 <-> x%i.fir#0: MayAlias
+// CHECK-DAG: x%p.fir#0 <-> x%i.fir#0: NoAlias
+// CHECK-DAG: x%x.fir#0 <-> x%p.fir#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
+}
+
+func.func @_QMmPtest.fir() {
+ %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 = fir.declare %0 {test.ptr = "x.fir", 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}>>
+ %2 = fir.field_index x, !fir.type<_QMmTt2{x:!fir.type<_QMmTt1{p:!fir.box<!fir.ptr<i32>>}>,p:!fir.box<!fir.ptr<i32>>,i:i32}>
+ %3 = fir.coordinate_of %1, %2 {test.ptr="x%x.fir"} : (!fir.ref<!fir.type<_QMmTt2{x:!fir.type<_QMmTt1{p:!fir.box<!fir.ptr<i32>>}>,p:!fir.box<!fir.ptr<i32>>,i:i32}>>, !fir.field) -> !fir.ref<!fir.type<_QMmTt1{p:!fir.box<!fir.ptr<i32>>}>>
+ %4 = fir.field_index p, !fir.type<_QMmTt2{x:!fir.type<_QMmTt1{p:!fir.box<!fir.ptr<i32>>}>,p:!fir.box<!fir.ptr<i32>>,i:i32}>
+ %5 = fir.coordinate_of %1, %4 {test.ptr="x%p.fir"} : (!fir.ref<!fir.type<_QMmTt2{x:!fir.type<_QMmTt1{p:!fir.box<!fir.ptr<i32>>}>,p:!fir.box<!fir.ptr<i32>>,i:i32}>>, !fir.field) -> !fir.ref<!fir.box<!fir.ptr<i32>>>
+ %6 = fir.field_index i, !fir.type<_QMmTt2{x:!fir.type<_QMmTt1{p:!fir.box<!fir.ptr<i32>>}>,p:!fir.box<!fir.ptr<i32>>,i:i32}>
+ %7 = fir.coordinate_of %1, %6 {test.ptr="x%i.fir"} : (!fir.ref<!fir.type<_QMmTt2{x:!fir.type<_QMmTt1{p:!fir.box<!fir.ptr<i32>>}>,p:!fir.box<!fir.ptr<i32>>,i:i32}>>, !fir.field) -> !fir.ref<i32>
+ %8 = fir.field_index p, !fir.type<_QMmTt1{p:!fir.box<!fir.ptr<i32>>}>
+ %9 = fir.coordinate_of %3, %8 {test.ptr="x%x%p.fir"} : (!fir.ref<!fir.type<_QMmTt1{p:!fir.box<!fir.ptr<i32>>}>>, !fir.field) -> !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.fir#0 <-> arg.fir#0: MayAlias
+// CHECK-DAG: argp.fir#0 <-> arg%p.fir#0: MayAlias
+// CHECK-DAG: argp.fir#0 <-> arg%i.fir#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: argp.tgt.fir#0 <-> arg.fir#0: NoAlias
+// CHECK-DAG: argp.tgt.fir#0 <-> arg%p.fir#0: NoAlias
+// CHECK-DAG: argp.tgt.fir#0 <-> arg%i.fir#0: NoAlias
+//
+// CHECK-DAG: arga#0 <-> arg#0: NoAlias
+// CHECK-DAG: arga#0 <-> arg%p#0: NoAlias
+// CHECK-DAG: arga.fir#0 <-> arg.fir#0: NoAlias
+// CHECK-DAG: arga.fir#0 <-> arg%p.fir#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.fir#0 <-> glob.fir#0: MayAlias
+// CHECK-DAG: argp.fir#0 <-> glob%p.fir#0: MayAlias
+// CHECK-DAG: argp.fir#0 <-> glob%i.fir#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: argp.tgt.fir#0 <-> glob.fir#0: NoAlias
+// CHECK-DAG: argp.tgt.fir#0 <-> glob%p.fir#0: NoAlias
+// CHECK-DAG: argp.tgt.fir#0 <-> glob%i.fir#0: NoAlias
+//
+// CHECK-DAG: arga#0 <-> glob#0: NoAlias
+// CHECK-DAG: arga#0 <-> glob%p#0: NoAlias
+// CHECK-DAG: arga.fir#0 <-> glob.fir#0: NoAlias
+// CHECK-DAG: arga.fir#0 <-> glob%p.fir#0: NoAlias
+
+// Check when composite is a local and thus cannot alias a dummy arg.
+//
+// CHECK-DAG: argp#0 <-> loc#0: NoAlias
+// CHECK-DAG: argp#0 <-> loc%p#0: NoAlias
+// CHECK-DAG: argp#0 <-> loc%i#0: NoAlias
+// CHECK-DAG: argp.fir#0 <-> loc.fir#0: NoAlias
+// CHECK-DAG: argp.fir#0 <-> loc%p.fir#0: NoAlias
+// CHECK-DAG: argp.fir#0 <-> loc%i.fir#0: NoAlias
+//
+// CHECK-DAG: argp.tgt#0 <-> loc#0: NoAlias
+// CHECK-DAG: argp.tgt#0 <-> loc%p#0: NoAlias
+// CHECK-DAG: argp.tgt#0 <-> loc%i#0: NoAlias
+// CHECK-DAG: argp.tgt.fir#0 <-> loc.fir#0: NoAlias
+// CHECK-DAG: argp.tgt.fir#0 <-> loc%p.fir#0: NoAlias
+// CHECK-DAG: argp.tgt.fir#0 <-> loc%i.fir#0: NoAlias
+//
+// CHECK-DAG: arga#0 <-> loc#0: NoAlias
+// CHECK-DAG: arga#0 <-> loc%p#0: NoAlias
+// CHECK-DAG: arga.fir#0 <-> loc.fir#0: NoAlias
+// CHECK-DAG: arga.fir#0 <-> loc%p.fir#0: NoAlias
+
+fir.global @_QMmEglob : !fir.type<_QMmTt{p:!fir.box<!fir.ptr<i32>>,i:i32}>
+
+func.func @_QMmPtest(%arg0: !fir.ref<!fir.box<!fir.ptr<i32>>> {fir.bindc_name = "argp"}, %arg1: !fir.ref<!fir.box<!fir.heap<i32>>> {fir.bindc_name = "arga"}, %arg2: !fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.ptr<i32>>,i:i32}>> {fir.bindc_name = "arg"}) {
+ %0 = fir.dummy_scope : !fir.dscope
+
+ %1:2 = hlfir.declare %arg0 dummy_scope %0 {test.ptr="argp", fortran_attrs = #fir.var_attrs<pointer>, uniq_name = "_QMmFtestEargp"} : (!fir.ref<!fir.box<!fir.ptr<i32>>>, !fir.dscope) -> (!fir.ref<!fir.box<!fir.ptr<i32>>>, !fir.ref<!fir.box<!fir.ptr<i32>>>)
+ %2 = fir.load %1#0 : !fir.ref<!fir.box<!fir.ptr<i32>>>
+ %3 = fir.box_addr %2 {test.ptr="argp.tgt"} : (!fir.box<!fir.ptr<i32>>) -> !fir.ptr<i32>
+
+ %4:2 = hlfir.declare %arg1 dummy_scope %0 {test.ptr="arga", fortran_attrs = #fir.var_attrs<allocatable>, uniq_name = "_QMmFtestEarga"} : (!fir.ref<!fir.box<!fir.heap<i32>>>, !fir.dscope) -> (!fir.ref<!fir.box<!fir.heap<i32>>>, !fir.ref<!fir.box<!fir.heap<i32>>>)
+
+ %5:2 = hlfir.declare %arg2 dummy_scope %0 {test.ptr="arg", uniq_name = "_QMmFtestEarg"} : (!fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.ptr<i32>>,i:i32}>>, !fir.dscope) -> (!fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.ptr<i32>>,i:i32}>>, !fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.ptr<i32>>,i:i32}>>)
+ %6 = hlfir.designate %5#0{"p"} {test.ptr="arg%p", fortran_attrs = #fir.var_attrs<pointer>} : (!fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.ptr<i32>>,i:i32}>>) -> !fir.ref<!fir.box<!fir.ptr<i32>>>
+ %7 = hlfir.designate %5#0{"i"} {test.ptr="arg%i"} : (!fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.ptr<i32>>,i:i32}>>) -> !fir.ref<i32>
+
+ %8 = fir.address_of(@_QMmEglob) : !fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.ptr<i32>>,i:i32}>>
+ %9:2 = hlfir.declare %8 {test.ptr="glob", uniq_name = "_QMmEglob"} : (!fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.ptr<i32>>,i:i32}>>) -> (!fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.ptr<i32>>,i:i32}>>, !fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.ptr<i32>>,i:i32}>>)
+ %10 = hlfir.designate %9#0{"p"} {test.ptr="glob%p", fortran_attrs = #fir.var_attrs<pointer>} : (!fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.ptr<i32>>,i:i32}>>) -> !fir.ref<!fir.box<!fir.ptr<i32>>>
+ %11 = hlfir.designate %9#0{"i"} {test.ptr="glob%i"} : (!fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.ptr<i32>>,i:i32}>>) -> !fir.ref<i32>
+
+ %12 = fir.alloca !fir.type<_QMmTt{p:!fir.box<!fir.ptr<i32>>,i:i32}> {bindc_name = "loc", uniq_name = "_QMmFtestEloc"}
+ %13:2 = hlfir.declare %12 {test.ptr="loc", uniq_name = "_QMmFtestEloc"} : (!fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.ptr<i32>>,i:i32}>>) -> (!fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.ptr<i32>>,i:i32}>>, !fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.ptr<i32>>,i:i32}>>)
+ %14 = hlfir.designate %13#0{"p"} {test.ptr="loc%p", fortran_attrs = #fir.var_attrs<pointer>} : (!fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.ptr<i32>>,i:i32}>>) -> !fir.ref<!fir.box<!fir.ptr<i32>>>
+ %15 = hlfir.designate %13#0{"i"} {test.ptr="loc%i"} : (!fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.ptr<i32>>,i:i32}>>) -> !fir.ref<i32>
+
+ return
+}
+
+func.func @_QMmPtest.fir(%arg0: !fir.ref<!fir.box<!fir.ptr<i32>>> {fir.bindc_name = "argp"}, %arg1: !fir.ref<!fir.box<!fir.heap<i32>>> {fir.bindc_name = "arga"}, %arg2: !fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.ptr<i32>>,i:i32}>> {fir.bindc_name = "arg"}) {
+ %0 = fir.dummy_scope : !fir.dscope
+
+ %1 = fir.declare %arg0 dummy_scope %0 {fortran_attrs = #fir.var_attrs<pointer>, test.ptr = "argp.fir", uniq_name = "_QMmFtestEargp"} : (!fir.ref<!fir.box<!fir.ptr<i32>>>, !fir.dscope) -> !fir.ref<!fir.box<!fir.ptr<i32>>>
+ %2 = fir.load %1 : !fir.ref<!fir.box<!fir.ptr<i32>>>
+ %3 = fir.box_addr %2 {test.ptr = "argp.tgt.fir"} : (!fir.box<!fir.ptr<i32>>) -> !fir.ptr<i32>
+
+ %4 = fir.declare %arg1 dummy_scope %0 {fortran_attrs = #fir.var_attrs<allocatable>, test.ptr = "arga.fir", uniq_name = "_QMmFtestEarga"} : (!fir.ref<!fir.box<!fir.heap<i32>>>, !fir.dscope) -> !fir.ref<!fir.box<!fir.heap<i32>>>
+
+ %5 = fir.declare %arg2 dummy_scope %0 {test.ptr = "arg.fir", uniq_name = "_QMmFtestEarg"} : (!fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.ptr<i32>>,i:i32}>>, !fir.dscope) -> !fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.ptr<i32>>,i:i32}>>
+ %6 = fir.field_index p, !fir.type<_QMmTt{p:!fir.box<!fir.ptr<i32>>,i:i32}>
+ %7 = fir.coordinate_of %5, %6 {test.ptr="arg%p.fir"} : (!fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.ptr<i32>>,i:i32}>>, !fir.field) -> !fir.ref<!fir.box<!fir.ptr<i32>>>
+ %8 = fir.field_index i, !fir.type<_QMmTt{p:!fir.box<!fir.ptr<i32>>,i:i32}>
+ %9 = fir.coordinate_of %5, %8 {test.ptr="arg%i.fir"} : (!fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.ptr<i32>>,i:i32}>>, !fir.field) -> !fir.ref<i32>
+
+ %10 = fir.address_of(@_QMmEglob) : !fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.ptr<i32>>,i:i32}>>
+ %11 = fir.declare %10 {test.ptr = "glob.fir", uniq_name = "_QMmEglob"} : (!fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.ptr<i32>>,i:i32}>>) -> !fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.ptr<i32>>,i:i32}>>
+ %12 = fir.field_index p, !fir.type<_QMmTt{p:!fir.box<!fir.ptr<i32>>,i:i32}>
+ %13 = fir.coordinate_of %11, %12 {test.ptr="glob%p.fir"} : (!fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.ptr<i32>>,i:i32}>>, !fir.field) -> !fir.ref<!fir.box<!fir.ptr<i32>>>
+ %14 = fir.field_index i, !fir.type<_QMmTt{p:!fir.box<!fir.ptr<i32>>,i:i32}>
+ %15 = fir.coordinate_of %11, %14 {test.ptr="glob%i.fir"} : (!fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.ptr<i32>>,i:i32}>>, !fir.field) -> !fir.ref<i32>
+
+ %16 = fir.alloca !fir.type<_QMmTt{p:!fir.box<!fir.ptr<i32>>,i:i32}> {bindc_name = "loc", uniq_name = "_QMmFtestEloc"}
+ %17 = fir.declare %16 {test.ptr = "loc.fir", uniq_name = "_QMmFtestEloc"} : (!fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.ptr<i32>>,i:i32}>>) -> !fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.ptr<i32>>,i:i32}>>
+ %18 = fir.field_index p, !fir.type<_QMmTt{p:!fir.box<!fir.ptr<i32>>,i:i32}>
+ %19 = fir.coordinate_of %17, %18 {test.ptr="loc%p.fir"} : (!fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.ptr<i32>>,i:i32}>>, !fir.field) -> !fir.ref<!fir.box<!fir.ptr<i32>>>
+ %20 = fir.field_index i, !fir.type<_QMmTt{p:!fir.box<!fir.ptr<i32>>,i:i32}>
+ %21 = fir.coordinate_of %17, %20 {test.ptr="loc%i.fir"} : (!fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.ptr<i32>>,i:i32}>>, !fir.field) -> !fir.ref<i32>
+
+ return
+}
+
+// -----
+
+// Same as previous case but argp and arga are HostAssoc.
+
+// module m
+// type t
+// integer, pointer :: p
+// integer i
+// end type
+// type(t) :: glob
+// contains
+// subroutine parent(argp, arga)
+// integer, pointer :: argp
+// integer, allocatable :: arga
+// type(t) :: arg
+// call test(arg)
+// contains
+// subroutine test(arg)
+// type(t) :: arg
+// type(t) :: loc
+// end subroutine
+// end subroutine
+// end module
+
+// CHECK-LABEL: Testing : "_QMmFparentPtest"
+
+// 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.fir#0 <-> arg.fir#0: MayAlias
+// CHECK-DAG: argp.fir#0 <-> arg%p.fir#0: MayAlias
+// CHECK-DAG: argp.fir#0 <-> arg%i.fir#0: NoAlias
+//
+// TODO: Shouldn't these be NoAlias? However, argp.tgt is currently handled as
+// Indirect.
+// CHECK-DAG: argp.tgt#0 <-> arg#0: MayAlias
+// CHECK-DAG: argp.tgt#0 <-> arg%p#0: MayAlias
+// CHECK-DAG: argp.tgt#0 <-> arg%i#0: MayAlias
+// CHECK-DAG: argp.tgt.fir#0 <-> arg.fir#0: MayAlias
+// CHECK-DAG: argp.tgt.fir#0 <-> arg%p.fir#0: MayAlias
+// CHECK-DAG: argp.tgt.fir#0 <-> arg%i.fir#0: MayAlias
+//
+// CHECK-DAG: arga#0 <-> arg#0: NoAlias
+// CHECK-DAG: arga#0 <-> arg%p#0: NoAlias
+// CHECK-DAG: arga.fir#0 <-> arg.fir#0: NoAlias
+// CHECK-DAG: arga.fir#0 <-> arg%p.fir#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.fir#0 <-> glob.fir#0: MayAlias
+// CHECK-DAG: argp.fir#0 <-> glob%p.fir#0: MayAlias
+// CHECK-DAG: argp.fir#0 <-> glob%i.fir#0: NoAlias
+//
+// TODO: Shouldn't these be NoAlias? However, argp.tgt is currently handled as
+// Indirect.
+// CHECK-DAG: argp.tgt#0 <-> glob#0: MayAlias
+// CHECK-DAG: argp.tgt#0 <-> glob%p#0: MayAlias
+// CHECK-DAG: argp.tgt#0 <-> glob%i#0: MayAlias
+// CHECK-DAG: argp.tgt.fir#0 <-> glob.fir#0: MayAlias
+// CHECK-DAG: argp.tgt.fir#0 <-> glob%p.fir#0: MayAlias
+// CHECK-DAG: argp.tgt.fir#0 <-> glob%i.fir#0: MayAlias
+//
+// CHECK-DAG: arga#0 <-> glob#0: NoAlias
+// CHECK-DAG: arga#0 <-> glob%p#0: NoAlias
+// CHECK-DAG: arga.fir#0 <-> glob.fir#0: NoAlias
+// CHECK-DAG: arga.fir#0 <-> glob%p.fir#0: NoAlias
+
+// Check when composite is a local and thus cannot alias a dummy arg.
+//
+// CHECK-DAG: argp#0 <-> loc#0: NoAlias
+// CHECK-DAG: argp#0 <-> loc%p#0: NoAlias
+// CHECK-DAG: argp#0 <-> loc%i#0: NoAlias
+// CHECK-DAG: argp.fir#0 <-> loc.fir#0: NoAlias
+// CHECK-DAG: argp.fir#0 <-> loc%p.fir#0: NoAlias
+// CHECK-DAG: argp.fir#0 <-> loc%i.fir#0: NoAlias
+//
+// TODO: Shouldn't these be NoAlias? However, argp.tgt is currently handled as
+// Indirect.
+// CHECK-DAG: argp.tgt#0 <-> loc#0: MayAlias
+// CHECK-DAG: argp.tgt#0 <-> loc%p#0: MayAlias
+// CHECK-DAG: argp.tgt#0 <-> loc%i#0: MayAlias
+// CHECK-DAG: argp.tgt.fir#0 <-> loc.fir#0: MayAlias
+// CHECK-DAG: argp.tgt.fir#0 <-> loc%p.fir#0: MayAlias
+// CHECK-DAG: argp.tgt.fir#0 <-> loc%i.fir#0: MayAlias
+//
+// CHECK-DAG: arga#0 <-> loc#0: NoAlias
+// CHECK-DAG: arga#0 <-> loc%p#0: NoAlias
+// CHECK-DAG: arga.fir#0 <-> loc.fir#0: NoAlias
+// CHECK-DAG: arga.fir#0 <-> loc%p.fir#0: NoAlias
+
+fir.global @_QMmEglob : !fir.type<_QMmTt{p:!fir.box<!fir.ptr<i32>>,i:i32}>
+
+func.func private @_QMmFparentPtest(%arg0: !fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.ptr<i32>>,i:i32}>> {fir.bindc_name = "arg"}, %arg1: !fir.ref<tuple<!fir.ref<!fir.box<!fir.ptr<i32>>>, !fir.ref<!fir.box<!fir.heap<i32>>>>> {fir.host_assoc}) attributes {fir.host_symbol = @_QMmPparent, llvm.linkage = #llvm.linkage<internal>} {
+ %0 = fir.dummy_scope : !fir.dscope
+
+ %c0_i32 = arith.constant 0 : i32
+ %1 = fir.coordinate_of %arg1, %c0_i32 : (!fir.ref<tuple<!fir.ref<!fir.box<!fir.ptr<i32>>>, !fir.ref<!fir.box<!fir.heap<i32>>>>>, i32) -> !fir.llvm_ptr<!fir.ref<!fir.box<!fir.ptr<i32>>>>
+ %2 = fir.load %1 : !fir.llvm_ptr<!fir.ref<!fir.box<!fir.ptr<i32>>>>
+ %3:2 = hlfir.declare %2 {test.ptr="argp", fortran_attrs = #fir.var_attrs<pointer, host_assoc>, uniq_name = "_QMmFparentEargp"} : (!fir.ref<!fir.box<!fir.ptr<i32>>>) -> (!fir.ref<!fir.box<!fir.ptr<i32>>>, !fir.ref<!fir.box<!fir.ptr<i32>>>)
+ %4 = fir.load %3#0 : !fir.ref<!fir.box<!fir.ptr<i32>>>
+ %5 = fir.box_addr %4 {test.ptr="argp.tgt"} : (!fir.box<!fir.ptr<i32>>) -> !fir.ptr<i32>
+
+ %c1_i32 = arith.constant 1 : i32
+ %10 = fir.coordinate_of %arg1, %c1_i32 : (!fir.ref<tuple<!fir.ref<!fir.box<!fir.ptr<i32>>>, !fir.ref<!fir.box<!fir.heap<i32>>>>>, i32) -> !fir.llvm_ptr<!fir.ref<!fir.box<!fir.heap<i32>>>>
+ %11 = fir.load %10 : !fir.llvm_ptr<!fir.ref<!fir.box<!fir.heap<i32>>>>
+ %12:2 = hlfir.declare %11 {test.ptr="arga", fortran_attrs = #fir.var_attrs<allocatable, host_assoc>, uniq_name = "_QMmFparentEarga"} : (!fir.ref<!fir.box<!fir.heap<i32>>>) -> (!fir.ref<!fir.box<!fir.heap<i32>>>, !fir.ref<!fir.box<!fir.heap<i32>>>)
+
+ %20 = fir.address_of(@_QMmEglob) : !fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.ptr<i32>>,i:i32}>>
+ %21:2 = hlfir.declare %20 {test.ptr="glob", uniq_name = "_QMmEglob"} : (!fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.ptr<i32>>,i:i32}>>) -> (!fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.ptr<i32>>,i:i32}>>, !fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.ptr<i32>>,i:i32}>>)
+ %22 = hlfir.designate %21#0{"p"} {test.ptr="glob%p", fortran_attrs = #fir.var_attrs<pointer>} : (!fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.ptr<i32>>,i:i32}>>) -> !fir.ref<!fir.box<!fir.ptr<i32>>>
+ %23 = hlfir.designate %21#0{"i"} {test.ptr="glob%i"} : (!fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.ptr<i32>>,i:i32}>>) -> !fir.ref<i32>
+
+ %30:2 = hlfir.declare %arg0 dummy_scope %0 {test.ptr="arg", uniq_name = "_QMmFparentFtestEarg"} : (!fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.ptr<i32>>,i:i32}>>, !fir.dscope) -> (!fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.ptr<i32>>,i:i32}>>, !fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.ptr<i32>>,i:i32}>>)
+ %31 = hlfir.designate %30#0{"p"} {test.ptr="arg%p", fortran_attrs = #fir.var_attrs<pointer>} : (!fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.ptr<i32>>,i:i32}>>) -> !fir.ref<!fir.box<!fir.ptr<i32>>>
+ %32 = hlfir.designate %30#0{"i"} {test.ptr="arg%i"} : (!fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.ptr<i32>>,i:i32}>>) -> !fir.ref<i32>
+
+ %40 = fir.alloca !fir.type<_QMmTt{p:!fir.box<!fir.ptr<i32>>,i:i32}> {bindc_name = "loc", uniq_name = "_QMmFparentFtestEloc"}
+ %41:2 = hlfir.declare %40 {test.ptr="loc", uniq_name = "_QMmFparentFtestEloc"} : (!fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.ptr<i32>>,i:i32}>>) -> (!fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.ptr<i32>>,i:i32}>>, !fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.ptr<i32>>,i:i32}>>)
+ %42 = hlfir.designate %41#0{"p"} {test.ptr="loc%p", fortran_attrs = #fir.var_attrs<pointer>} : (!fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.ptr<i32>>,i:i32}>>) -> !fir.ref<!fir.box<!fir.ptr<i32>>>
+ %43 = hlfir.designate %41#0{"i"} {test.ptr="loc%i"} : (!fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.ptr<i32>>,i:i32}>>) -> !fir.ref<i32>
+
+ return
+}
+
+func.func private @_QMmFparentPtest.fir(%arg0: !fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.ptr<i32>>,i:i32}>> {fir.bindc_name = "arg"}, %arg1: !fir.ref<tuple<!fir.ref<!fir.box<!fir.ptr<i32>>>, !fir.ref<!fir.box<!fir.heap<i32>>>>> {fir.host_assoc}) attributes {fir.host_symbol = @_QMmPparent, llvm.linkage = #llvm.linkage<internal>} {
+ %0 = fir.dummy_scope : !fir.dscope
+
+ %c0_i32 = arith.constant 0 : i32
+ %1 = fir.coordinate_of %arg1, %c0_i32 : (!fir.ref<tuple<!fir.ref<!fir.box<!fir.ptr<i32>>>, !fir.ref<!fir.box<!fir.heap<i32>>>>>, i32) -> !fir.llvm_ptr<!fir.ref<!fir.box<!fir.ptr<i32>>>>
+ %2 = fir.load %1 : !fir.llvm_ptr<!fir.ref<!fir.box<!fir.ptr<i32>>>>
+ %3 = fir.declare %2 {fortran_attrs = #fir.var_attrs<pointer, host_assoc>, test.ptr = "argp.fir", uniq_name = "_QMmFparentEargp"} : (!fir.ref<!fir.box<!fir.ptr<i32>>>) -> !fir.ref<!fir.box<!fir.ptr<i32>>>
+ %4 = fir.load %3 : !fir.ref<!fir.box<!fir.ptr<i32>>>
+ %5 = fir.box_addr %4 {test.ptr = "argp.tgt.fir"} : (!fir.box<!fir.ptr<i32>>) -> !fir.ptr<i32>
+
+ %c1_i32 = arith.constant 1 : i32
+ %6 = fir.coordinate_of %arg1, %c1_i32 : (!fir.ref<tuple<!fir.ref<!fir.box<!fir.ptr<i32>>>, !fir.ref<!fir.box<!fir.heap<i32>>>>>, i32) -> !fir.llvm_ptr<!fir.ref<!fir.box<!fir.heap<i32>>>>
+ %7 = fir.load %6 : !fir.llvm_ptr<!fir.ref<!fir.box<!fir.heap<i32>>>>
+ %8 = fir.declare %7 {fortran_attrs = #fir.var_attrs<allocatable, host_assoc>, test.ptr = "arga.fir", uniq_name = "_QMmFparentEarga"} : (!fir.ref<!fir.box<!fir.heap<i32>>>) -> !fir.ref<!fir.box<!fir.heap<i32>>>
+
+ %9 = fir.address_of(@_QMmEglob) : !fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.ptr<i32>>,i:i32}>>
+ %10 = fir.declare %9 {test.ptr = "glob.fir", uniq_name = "_QMmEglob"} : (!fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.ptr<i32>>,i:i32}>>) -> !fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.ptr<i32>>,i:i32}>>
+ %11 = fir.field_index p, !fir.type<_QMmTt{p:!fir.box<!fir.ptr<i32>>,i:i32}>
+ %12 = fir.coordinate_of %10, %11 {test.ptr="glob%p.fir"} : (!fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.ptr<i32>>,i:i32}>>, !fir.field) -> !fir.ref<!fir.box<!fir.ptr<i32>>>
+ %13 = fir.field_index i, !fir.type<_QMmTt{p:!fir.box<!fir.ptr<i32>>,i:i32}>
+ %14 = fir.coordinate_of %10, %13 {test.ptr="glob%i.fir"} : (!fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.ptr<i32>>,i:i32}>>, !fir.field) -> !fir.ref<i32>
+
+ %15 = fir.declare %arg0 dummy_scope %0 {test.ptr = "arg.fir", uniq_name = "_QMmFparentFtestEarg"} : (!fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.ptr<i32>>,i:i32}>>, !fir.dscope) -> !fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.ptr<i32>>,i:i32}>>
+ %16 = fir.field_index p, !fir.type<_QMmTt{p:!fir.box<!fir.ptr<i32>>,i:i32}>
+ %17 = fir.coordinate_of %15, %16 {test.ptr="arg%p.fir"} : (!fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.ptr<i32>>,i:i32}>>, !fir.field) -> !fir.ref<!fir.box<!fir.ptr<i32>>>
+ %18 = fir.field_index i, !fir.type<_QMmTt{p:!fir.box<!fir.ptr<i32>>,i:i32}>
+ %19 = fir.coordinate_of %15, %18 {test.ptr="arg%i.fir"} : (!fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.ptr<i32>>,i:i32}>>, !fir.field) -> !fir.ref<i32>
+
+ %20 = fir.alloca !fir.type<_QMmTt{p:!fir.box<!fir.ptr<i32>>,i:i32}> {bindc_name = "loc", uniq_name = "_QMmFparentFtestEloc"}
+ %21 = fir.declare %20 {test.ptr = "loc.fir", uniq_name = "_QMmFparentFtestEloc"} : (!fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.ptr<i32>>,i:i32}>>) -> !fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.ptr<i32>>,i:i32}>>
+ %22 = fir.field_index p, !fir.type<_QMmTt{p:!fir.box<!fir.ptr<i32>>,i:i32}>
+ %23 = fir.coordinate_of %21, %22 {test.ptr="loc%p.fir"} : (!fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.ptr<i32>>,i:i32}>>, !fir.field) -> !fir.ref<!fir.box<!fir.ptr<i32>>>
+ %24 = fir.field_index i, !fir.type<_QMmTt{p:!fir.box<!fir.ptr<i32>>,i:i32}>
+ %25 = fir.coordinate_of %21, %24 {test.ptr="loc%i.fir"} : (!fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.ptr<i32>>,i:i32}>>, !fir.field) -> !fir.ref<i32>
+
+ return
+}
+
+// -----
+
+// Dummy arg with target attribute and pointer component.
+
+// The address of a dummy arg (arg0) may alias the address of a global (glob0)
+// or another dummy arg (arg1) when both have target attributes. If either is a
+// composite, the addresses of components (whether data like r, or non-data like
+// p and a) may also alias the composite or the same component. However, target
+// attributes do not permit two globals (glob0 and glob1) to alias.
+
+// module m
+// type t
+// real, pointer :: p
+// real, allocatable :: a
+// real :: r
+// end type
+// type(t), target :: glob0
+// type(t), target :: glob1
+// contains
+// subroutine test(arg0, arg1)
+// type(t), target :: arg0
+// type(t), target :: arg1
+// end subroutine
+// end module
+
+// TODO: All glob0 vs. glob1 cases can be NoAlias. However, AliasAnalysis
+// currently indiscriminately treats all targets that are data (addresses of
+// glob[01] and glob[01]%r but not glob[01]%p and glob[01]%a) as aliasing.
+
+// Check composite vs. composite.
+//
+// CHECK-DAG: arg0#0 <-> arg1#0: MayAlias
+// CHECK-DAG: arg0.fir#0 <-> arg1.fir#0: MayAlias
+//
+// CHECK-DAG: arg0#0 <-> glob0#0: MayAlias
+// CHECK-DAG: arg0.fir#0 <-> glob0.fir#0: MayAlias
+//
+// CHECK-DAG: glob0#0 <-> glob1#0: MayAlias
+// CHECK-DAG: glob0.fir#0 <-> glob1.fir#0: MayAlias
+
+// Check component vs. composite.
+//
+// CHECK-DAG: arg0%p#0 <-> arg1#0: MayAlias
+// CHECK-DAG: arg0%a#0 <-> arg1#0: MayAlias
+// CHECK-DAG: arg0%r#0 <-> arg1#0: MayAlias
+// CHECK-DAG: arg0%p.fir#0 <-> arg1.fir#0: MayAlias
+// CHECK-DAG: arg0%a.fir#0 <-> arg1.fir#0: MayAlias
+// CHECK-DAG: arg0%r.fir#0 <-> arg1.fir#0: MayAlias
+//
+// CHECK-DAG: arg0%p#0 <-> glob0#0: MayAlias
+// CHECK-DAG: arg0%a#0 <-> glob0#0: MayAlias
+// CHECK-DAG: arg0%r#0 <-> glob0#0: MayAlias
+// CHECK-DAG: arg0%p.fir#0 <-> glob0.fir#0: MayAlias
+// CHECK-DAG: arg0%a.fir#0 <-> glob0.fir#0: MayAlias
+// CHECK-DAG: arg0%r.fir#0 <-> glob0.fir#0: MayAlias
+//
+// CHECK-DAG: glob0%p#0 <-> glob1#0: NoAlias
+// CHECK-DAG: glob0%a#0 <-> glob1#0: NoAlias
+// CHECK-DAG: glob0%r#0 <-> glob1#0: MayAlias
+// CHECK-DAG: glob0%p.fir#0 <-> glob1.fir#0: NoAlias
+// CHECK-DAG: glob0%a.fir#0 <-> glob1.fir#0: NoAlias
+// CHECK-DAG: glob0%r.fir#0 <-> glob1.fir#0: MayAlias
+
+// Check composite vs. component.
+//
+// CHECK-DAG: arg0#0 <-> arg1%p#0: MayAlias
+// CHECK-DAG: arg0#0 <-> arg1%a#0: MayAlias
+// CHECK-DAG: arg0#0 <-> arg1%r#0: MayAlias
+// CHECK-DAG: arg0.fir#0 <-> arg1%p.fir#0: MayAlias
+// CHECK-DAG: arg0.fir#0 <-> arg1%a.fir#0: MayAlias
+// CHECK-DAG: arg0.fir#0 <-> arg1%r.fir#0: MayAlias
+//
+// CHECK-DAG: arg0#0 <-> glob0%p#0: MayAlias
+// CHECK-DAG: arg0#0 <-> glob0%a#0: MayAlias
+// CHECK-DAG: arg0#0 <-> glob0%r#0: MayAlias
+// CHECK-DAG: arg0.fir#0 <-> glob0%p.fir#0: MayAlias
+// CHECK-DAG: arg0.fir#0 <-> glob0%a.fir#0: MayAlias
+// CHECK-DAG: arg0.fir#0 <-> glob0%r.fir#0: MayAlias
+//
+// CHECK-DAG: glob0#0 <-> glob1%p#0: NoAlias
+// CHECK-DAG: glob0#0 <-> glob1%a#0: NoAlias
+// CHECK-DAG: glob0#0 <-> glob1%r#0: MayAlias
+// CHECK-DAG: glob0.fir#0 <-> glob1%p.fir#0: NoAlias
+// CHECK-DAG: glob0.fir#0 <-> glob1%a.fir#0: NoAlias
+// CHECK-DAG: glob0.fir#0 <-> glob1%r.fir#0: MayAlias
+
+// Check component vs. component.
+//
+// CHECK-DAG: arg0%p#0 <-> arg1%p#0: MayAlias
+// CHECK-DAG: arg0%a#0 <-> arg1%a#0: MayAlias
+// CHECK-DAG: arg0%r#0 <-> arg1%r#0: MayAlias
+// CHECK-DAG: arg0%p.fir#0 <-> arg1%p.fir#0: MayAlias
+// CHECK-DAG: arg0%a.fir#0 <-> arg1%a.fir#0: MayAlias
+// CHECK-DAG: arg0%r.fir#0 <-> arg1%r.fir#0: MayAlias
+//
+// CHECK-DAG: arg0%p.fir#0 <-> glob0%p.fir#0: MayAlias
+// CHECK-DAG: arg0%a.fir#0 <-> glob0%a.fir#0: MayAlias
+// CHECK-DAG: arg0%r.fir#0 <-> glob0%r.fir#0: MayAlias
+//
+// CHECK-DAG: glob0%p.fir#0 <-> glob1%p.fir#0: NoAlias
+// CHECK-DAG: glob0%a.fir#0 <-> glob1%a.fir#0: NoAlias
+// CHECK-DAG: glob0%r.fir#0 <-> glob1%r.fir#0: MayAlias
+
+func.func @_QMmPtest(%arg0: !fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.ptr<f32>>,a:!fir.box<!fir.heap<f32>>,r:f32}>> {fir.bindc_name = "arg0", fir.target}, %arg1: !fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.ptr<f32>>,a:!fir.box<!fir.heap<f32>>,r:f32}>> {fir.bindc_name = "arg1", fir.target}) {
+ %0 = fir.dummy_scope : !fir.dscope
+
+ %10:2 = hlfir.declare %arg0 dummy_scope %0 {test.ptr="arg0", fortran_attrs = #fir.var_attrs<target>, uniq_name = "_QMmFtestEarg0"} : (!fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.ptr<f32>>,a:!fir.box<!fir.heap<f32>>,r:f32}>>, !fir.dscope) -> (!fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.ptr<f32>>,a:!fir.box<!fir.heap<f32>>,r:f32}>>, !fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.ptr<f32>>,a:!fir.box<!fir.heap<f32>>,r:f32}>>)
+ %11 = hlfir.designate %10#0{"p"} {test.ptr="arg0%p", fortran_attrs = #fir.var_attrs<pointer>} : (!fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.ptr<f32>>,a:!fir.box<!fir.heap<f32>>,r:f32}>>) -> !fir.ref<!fir.box<!fir.ptr<f32>>>
+ %12 = hlfir.designate %10#0{"a"} {test.ptr="arg0%a", fortran_attrs = #fir.var_attrs<allocatable>} : (!fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.ptr<f32>>,a:!fir.box<!fir.heap<f32>>,r:f32}>>) -> !fir.ref<!fir.box<!fir.heap<f32>>>
+ %13 = hlfir.designate %10#0{"r"} {test.ptr="arg0%r"} : (!fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.ptr<f32>>,a:!fir.box<!fir.heap<f32>>,r:f32}>>) -> !fir.ref<f32>
+
+ %20:2 = hlfir.declare %arg1 dummy_scope %0 {test.ptr="arg1", fortran_attrs = #fir.var_attrs<target>, uniq_name = "_QMmFtestEarg1"} : (!fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.ptr<f32>>,a:!fir.box<!fir.heap<f32>>,r:f32}>>, !fir.dscope) -> (!fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.ptr<f32>>,a:!fir.box<!fir.heap<f32>>,r:f32}>>, !fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.ptr<f32>>,a:!fir.box<!fir.heap<f32>>,r:f32}>>)
+ %21 = hlfir.designate %20#0{"p"} {test.ptr="arg1%p", fortran_attrs = #fir.var_attrs<pointer>} : (!fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.ptr<f32>>,a:!fir.box<!fir.heap<f32>>,r:f32}>>) -> !fir.ref<!fir.box<!fir.ptr<f32>>>
+ %22 = hlfir.designate %20#0{"a"} {test.ptr="arg1%a", fortran_attrs = #fir.var_attrs<allocatable>} : (!fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.ptr<f32>>,a:!fir.box<!fir.heap<f32>>,r:f32}>>) -> !fir.ref<!fir.box<!fir.heap<f32>>>
+ %23 = hlfir.designate %20#0{"r"} {test.ptr="arg1%r"} : (!fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.ptr<f32>>,a:!fir.box<!fir.heap<f32>>,r:f32}>>) -> !fir.ref<f32>
+
+ %30 = fir.address_of(@_QMmEglob0) : !fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.ptr<f32>>,a:!fir.box<!fir.heap<f32>>,r:f32}>>
+ %31:2 = hlfir.declare %30 {test.ptr="glob0", fortran_attrs = #fir.var_attrs<target>, uniq_name = "_QMmEglob0"} : (!fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.ptr<f32>>,a:!fir.box<!fir.heap<f32>>,r:f32}>>) -> (!fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.ptr<f32>>,a:!fir.box<!fir.heap<f32>>,r:f32}>>, !fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.ptr<f32>>,a:!fir.box<!fir.heap<f32>>,r:f32}>>)
+ %32 = hlfir.designate %31#0{"p"} {test.ptr="glob0%p", fortran_attrs = #fir.var_attrs<pointer>} : (!fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.ptr<f32>>,a:!fir.box<!fir.heap<f32>>,r:f32}>>) -> !fir.ref<!fir.box<!fir.ptr<f32>>>
+ %33 = hlfir.designate %31#0{"a"} {test.ptr="glob0%a", fortran_attrs = #fir.var_attrs<allocatable>} : (!fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.ptr<f32>>,a:!fir.box<!fir.heap<f32>>,r:f32}>>) -> !fir.ref<!fir.box<!fir.heap<f32>>>
+ %34 = hlfir.designate %31#0{"r"} {test.ptr="glob0%r"} : (!fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.ptr<f32>>,a:!fir.box<!fir.heap<f32>>,r:f32}>>) -> !fir.ref<f32>
+
+ %40 = fir.address_of(@_QMmEglob1) : !fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.ptr<f32>>,a:!fir.box<!fir.heap<f32>>,r:f32}>>
+ %41:2 = hlfir.declare %40 {test.ptr="glob1", fortran_attrs = #fir.var_attrs<target>, uniq_name = "_QMmEglob1"} : (!fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.ptr<f32>>,a:!fir.box<!fir.heap<f32>>,r:f32}>>) -> (!fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.ptr<f32>>,a:!fir.box<!fir.heap<f32>>,r:f32}>>, !fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.ptr<f32>>,a:!fir.box<!fir.heap<f32>>,r:f32}>>)
+ %42 = hlfir.designate %41#0{"p"} {test.ptr="glob1%p", fortran_attrs = #fir.var_attrs<pointer>} : (!fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.ptr<f32>>,a:!fir.box<!fir.heap<f32>>,r:f32}>>) -> !fir.ref<!fir.box<!fir.ptr<f32>>>
+ %43 = hlfir.designate %41#0{"a"} {test.ptr="glob1%a", fortran_attrs = #fir.var_attrs<allocatable>} : (!fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.ptr<f32>>,a:!fir.box<!fir.heap<f32>>,r:f32}>>) -> !fir.ref<!fir.box<!fir.heap<f32>>>
+ %44 = hlfir.designate %41#0{"r"} {test.ptr="glob1%r"} : (!fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.ptr<f32>>,a:!fir.box<!fir.heap<f32>>,r:f32}>>) -> !fir.ref<f32>
+
+ return
+}
+
+func.func @_QMmPtest.fir(%arg0: !fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.ptr<f32>>,a:!fir.box<!fir.heap<f32>>,r:f32}>> {fir.bindc_name = "arg0", fir.target}, %arg1: !fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.ptr<f32>>,a:!fir.box<!fir.heap<f32>>,r:f32}>> {fir.bindc_name = "arg1", fir.target}) {
+ %0 = fir.dummy_scope : !fir.dscope
+
+ %1 = fir.declare %arg0 dummy_scope %0 {test.ptr="arg0.fir", fortran_attrs = #fir.var_attrs<target>, uniq_name = "_QMmFtestEarg0"} : (!fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.ptr<f32>>,a:!fir.box<!fir.heap<f32>>,r:f32}>>, !fir.dscope) -> !fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.ptr<f32>>,a:!fir.box<!fir.heap<f32>>,r:f32}>>
+ %2 = fir.field_index p, !fir.type<_QMmTt{p:!fir.box<!fir.ptr<f32>>,a:!fir.box<!fir.heap<f32>>,r:f32}>
+ %3 = fir.coordinate_of %1, %2 {test.ptr="arg0%p.fir"} : (!fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.ptr<f32>>,a:!fir.box<!fir.heap<f32>>,r:f32}>>, !fir.field) -> !fir.ref<!fir.box<!fir.ptr<f32>>>
+ %4 = fir.field_index a, !fir.type<_QMmTt{p:!fir.box<!fir.ptr<f32>>,a:!fir.box<!fir.heap<f32>>,r:f32}>
+ %5 = fir.coordinate_of %1, %4 {test.ptr="arg0%a.fir"} : (!fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.ptr<f32>>,a:!fir.box<!fir.heap<f32>>,r:f32}>>, !fir.field) -> !fir.ref<!fir.box<!fir.heap<f32>>>
+ %6 = fir.field_index r, !fir.type<_QMmTt{p:!fir.box<!fir.ptr<f32>>,a:!fir.box<!fir.heap<f32>>,r:f32}>
+ %7 = fir.coordinate_of %1, %6 {test.ptr="arg0%r.fir"} : (!fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.ptr<f32>>,a:!fir.box<!fir.heap<f32>>,r:f32}>>, !fir.field) -> !fir.ref<f32>
+
+ %8 = fir.declare %arg1 dummy_scope %0 {test.ptr="arg1.fir", fortran_attrs = #fir.var_attrs<target>, uniq_name = "_QMmFtestEarg1"} : (!fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.ptr<f32>>,a:!fir.box<!fir.heap<f32>>,r:f32}>>, !fir.dscope) -> !fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.ptr<f32>>,a:!fir.box<!fir.heap<f32>>,r:f32}>>
+ %9 = fir.field_index p, !fir.type<_QMmTt{p:!fir.box<!fir.ptr<f32>>,a:!fir.box<!fir.heap<f32>>,r:f32}>
+ %10 = fir.coordinate_of %8, %9 {test.ptr="arg1%p.fir"} : (!fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.ptr<f32>>,a:!fir.box<!fir.heap<f32>>,r:f32}>>, !fir.field) -> !fir.ref<!fir.box<!fir.ptr<f32>>>
+ %11 = fir.field_index a, !fir.type<_QMmTt{p:!fir.box<!fir.ptr<f32>>,a:!fir.box<!fir.heap<f32>>,r:f32}>
+ %12 = fir.coordinate_of %8, %11 {test.ptr="arg1%a.fir"} : (!fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.ptr<f32>>,a:!fir.box<!fir.heap<f32>>,r:f32}>>, !fir.field) -> !fir.ref<!fir.box<!fir.heap<f32>>>
+ %13 = fir.field_index r, !fir.type<_QMmTt{p:!fir.box<!fir.ptr<f32>>,a:!fir.box<!fir.heap<f32>>,r:f32}>
+ %14 = fir.coordinate_of %8, %13 {test.ptr="arg1%r.fir"} : (!fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.ptr<f32>>,a:!fir.box<!fir.heap<f32>>,r:f32}>>, !fir.field) -> !fir.ref<f32>
+
+ %15 = fir.address_of(@_QMmEglob0) : !fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.ptr<f32>>,a:!fir.box<!fir.heap<f32>>,r:f32}>>
+ %16 = fir.declare %15 {test.ptr="glob0.fir", fortran_attrs = #fir.var_attrs<target>, uniq_name = "_QMmEglob0"} : (!fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.ptr<f32>>,a:!fir.box<!fir.heap<f32>>,r:f32}>>) -> !fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.ptr<f32>>,a:!fir.box<!fir.heap<f32>>,r:f32}>>
+ %17 = fir.field_index p, !fir.type<_QMmTt{p:!fir.box<!fir.ptr<f32>>,a:!fir.box<!fir.heap<f32>>,r:f32}>
+ %18 = fir.coordinate_of %16, %17 {test.ptr="glob0%p.fir"} : (!fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.ptr<f32>>,a:!fir.box<!fir.heap<f32>>,r:f32}>>, !fir.field) -> !fir.ref<!fir.box<!fir.ptr<f32>>>
+ %19 = fir.field_index a, !fir.type<_QMmTt{p:!fir.box<!fir.ptr<f32>>,a:!fir.box<!fir.heap<f32>>,r:f32}>
+ %20 = fir.coordinate_of %16, %19 {test.ptr="glob0%a.fir"} : (!fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.ptr<f32>>,a:!fir.box<!fir.heap<f32>>,r:f32}>>, !fir.field) -> !fir.ref<!fir.box<!fir.heap<f32>>>
+ %21 = fir.field_index r, !fir.type<_QMmTt{p:!fir.box<!fir.ptr<f32>>,a:!fir.box<!fir.heap<f32>>,r:f32}>
+ %22 = fir.coordinate_of %16, %21 {test.ptr="glob0%r.fir"} : (!fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.ptr<f32>>,a:!fir.box<!fir.heap<f32>>,r:f32}>>, !fir.field) -> !fir.ref<f32>
+
+ %23 = fir.address_of(@_QMmEglob1) : !fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.ptr<f32>>,a:!fir.box<!fir.heap<f32>>,r:f32}>>
+ %24 = fir.declare %23 {test.ptr="glob1.fir", fortran_attrs = #fir.var_attrs<target>, uniq_name = "_QMmEglob1"} : (!fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.ptr<f32>>,a:!fir.box<!fir.heap<f32>>,r:f32}>>) -> !fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.ptr<f32>>,a:!fir.box<!fir.heap<f32>>,r:f32}>>
+ %25 = fir.field_index p, !fir.type<_QMmTt{p:!fir.box<!fir.ptr<f32>>,a:!fir.box<!fir.heap<f32>>,r:f32}>
+ %26 = fir.coordinate_of %24, %25 {test.ptr="glob1%p.fir"} : (!fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.ptr<f32>>,a:!fir.box<!fir.heap<f32>>,r:f32}>>, !fir.field) -> !fir.ref<!fir.box<!fir.ptr<f32>>>
+ %27 = fir.field_index a, !fir.type<_QMmTt{p:!fir.box<!fir.ptr<f32>>,a:!fir.box<!fir.heap<f32>>,r:f32}>
+ %28 = fir.coordinate_of %24, %27 {test.ptr="glob1%a.fir"} : (!fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.ptr<f32>>,a:!fir.box<!fir.heap<f32>>,r:f32}>>, !fir.field) -> !fir.ref<!fir.box<!fir.heap<f32>>>
+ %29 = fir.field_index r, !fir.type<_QMmTt{p:!fir.box<!fir.ptr<f32>>,a:!fir.box<!fir.heap<f32>>,r:f32}>
+ %30 = fir.coordinate_of %24, %29 {test.ptr="glob1%r.fir"} : (!fir.ref<!fir.type<_QMmTt{p:!fir.box<!fir.ptr<f32>>,a:!fir.box<!fir.heap<f32>>,r:f32}>>, !fir.field) -> !fir.ref<f32>
+
+ return
+}
+
+// -----
+
+// Allocatable dummy arg with target attribute.
+
+// This case is like the previous one except that the non-data is the address
+// of the dummy arg itself rather than of a pointer component of the dummy arg.
+// The goal is to check that logic introduced into AliasAnalysis to handle the
+// pointer component case doesn't break this related one.
+
+// module m
+// real, allocatable, target :: glob0
+// real, allocatable, target :: glob1
+// contains
+// subroutine test(arg0, arg1)
+// real, allocatable, target :: arg0
+// real, allocatable, target :: arg1
+// end subroutine
+// end module
+
+// CHECK-DAG: arg0#0 <-> arg1#0: MayAlias
+// CHECK-DAG: arg0#0 <-> glob0#0: MayAlias
+// CHECK-DAG: glob0#0 <-> glob1#0: NoAlias
+
+func.func @_QMmPtest(%arg0: !fir.ref<!fir.box<!fir.heap<f32>>> {fir.bindc_name = "arg0", fir.target}, %arg1: !fir.ref<!fir.box<!fir.heap<f32>>> {fir.bindc_name = "arg1", fir.target}) {
+ %0 = fir.dummy_scope : !fir.dscope
+
+ %10:2 = hlfir.declare %arg0 dummy_scope %0 {test.ptr="arg0", fortran_attrs = #fir.var_attrs<allocatable, target>, uniq_name = "_QMmFtestEarg0"} : (!fir.ref<!fir.box<!fir.heap<f32>>>, !fir.dscope) -> (!fir.ref<!fir.box<!fir.heap<f32>>>, !fir.ref<!fir.box<!fir.heap<f32>>>)
+ %11:2 = hlfir.declare %arg1 dummy_scope %0 {test.ptr="arg1", fortran_attrs = #fir.var_attrs<allocatable, target>, uniq_name = "_QMmFtestEarg1"} : (!fir.ref<!fir.box<!fir.heap<f32>>>, !fir.dscope) -> (!fir.ref<!fir.box<!fir.heap<f32>>>, !fir.ref<!fir.box<!fir.heap<f32>>>)
+
+ %20 = fir.address_of(@_QMmEglob0) : !fir.ref<!fir.box<!fir.heap<f32>>>
+ %21:2 = hlfir.declare %20 {test.ptr="glob0", fortran_attrs = #fir.var_attrs<allocatable, target>, uniq_name = "_QMmEglob0"} : (!fir.ref<!fir.box<!fir.heap<f32>>>) -> (!fir.ref<!fir.box<!fir.heap<f32>>>, !fir.ref<!fir.box<!fir.heap<f32>>>)
+ %22 = fir.address_of(@_QMmEglob1) : !fir.ref<!fir.box<!fir.heap<f32>>>
+ %23:2 = hlfir.declare %22 {test.ptr="glob1", fortran_attrs = #fir.var_attrs<allocatable, target>, uniq_name = "_QMmEglob1"} : (!fir.ref<!fir.box<!fir.heap<f32>>>) -> (!fir.ref<!fir.box<!fir.heap<f32>>>, !fir.ref<!fir.box<!fir.heap<f32>>>)
+
+ return
+}
More information about the flang-commits
mailing list