[flang-commits] [flang] [flang] AliasAnalysis: Fix pointer component logic (PR #94242)
Joel E. Denny via flang-commits
flang-commits at lists.llvm.org
Thu Jun 20 09:04:41 PDT 2024
https://github.com/jdenny-ornl updated https://github.com/llvm/llvm-project/pull/94242
>From 484cb901cb3f5ae934b55629bb8537e42d3a832d Mon Sep 17 00:00:00 2001
From: "Joel E. Denny" <jdenny.ornl at gmail.com>
Date: Tue, 28 May 2024 19:14:22 -0400
Subject: [PATCH 1/9] WIP: [flang] AliasAnalysis: Fix pointer component logic
---
.../lib/Optimizer/Analysis/AliasAnalysis.cpp | 30 ++++++++++++-------
.../AliasAnalysis/alias-analysis-3.fir | 19 ++++++------
.../AliasAnalysis/alias-analysis-9.fir | 12 ++++----
3 files changed, 34 insertions(+), 27 deletions(-)
diff --git a/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp b/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp
index 9d0d706a85c5e..571b78dc64aa5 100644
--- a/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp
+++ b/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp
@@ -122,6 +122,18 @@ AliasResult AliasAnalysis::alias(Value lhs, Value rhs) {
}
if (lhsSrc.kind == rhsSrc.kind) {
+ // If the kinds and origins are the same, then lhs and rhs must alias unless
+ // either source is approximate. Approximate sources are for parts of the
+ // origin, but we don't have info here on which parts and whether they
+ // overlap, so we normally return MayAlias in that case.
+ //
+ // There is an exceptional case: The origins might compare unequal because
+ // only one has !isData(). If that source is approximate and the other is
+ // not, then the former is the source for the address *of* a pointer
+ // component in a composite, and the latter is for the address of that
+ // composite. As for the address of any composite vs. the address of one of
+ // its components, a store to one can affect a load from the other, so the
+ // result is MayAlias.
if (lhsSrc.origin == rhsSrc.origin) {
LLVM_DEBUG(llvm::dbgs()
<< " aliasing because same source kind and origin\n");
@@ -129,6 +141,13 @@ AliasResult AliasAnalysis::alias(Value lhs, Value rhs) {
return AliasResult::MayAlias;
return AliasResult::MustAlias;
}
+ if (lhsSrc.origin.u == rhsSrc.origin.u &&
+ ((lhsSrc.approximateSource && !lhsSrc.isData() && !rhsSrc.approximateSource) ||
+ (rhsSrc.approximateSource && !rhsSrc.isData() && !lhsSrc.approximateSource))) {
+ LLVM_DEBUG(llvm::dbgs()
+ << " aliasing between composite and pointer component\n");
+ return AliasResult::MayAlias;
+ }
// Two host associated accesses may overlap due to an equivalence.
if (lhsSrc.kind == SourceKind::HostAssoc) {
@@ -173,17 +192,6 @@ AliasResult AliasAnalysis::alias(Value lhs, Value rhs) {
return AliasResult::MayAlias;
}
- // Box for POINTER component inside an object of a derived type
- // may alias box of a POINTER object, as well as boxes for POINTER
- // components inside two objects of derived types may alias.
- if ((src1->isRecordWithPointerComponent() && src2->isTargetOrPointer()) ||
- (src2->isRecordWithPointerComponent() && src1->isTargetOrPointer()) ||
- (src1->isRecordWithPointerComponent() &&
- src2->isRecordWithPointerComponent())) {
- LLVM_DEBUG(llvm::dbgs() << " aliasing because of pointer components\n");
- return AliasResult::MayAlias;
- }
-
return AliasResult::NoAlias;
}
diff --git a/flang/test/Analysis/AliasAnalysis/alias-analysis-3.fir b/flang/test/Analysis/AliasAnalysis/alias-analysis-3.fir
index 91829a461dc72..2bf326f2d2af2 100644
--- a/flang/test/Analysis/AliasAnalysis/alias-analysis-3.fir
+++ b/flang/test/Analysis/AliasAnalysis/alias-analysis-3.fir
@@ -16,12 +16,12 @@
// end subroutine test
// end module m
-// A composite with a pointer component may alias with a dummy pointer
+// A composite with a pointer component does not alias with a dummy pointer
// CHECK-LABEL: Testing : "_QMmPtest
-// CHECK: a#0 <-> func.region0#0: MayAlias
+// CHECK: a#0 <-> func.region0#0: NoAlias
-// FIXME: a's box cannot alias with raw reference to f32 (x), so MayAlias below must be NoAlias:
-// CHECK: a#0 <-> func.region0#1: MayAlias
+// a's box cannot alias with raw reference to f32 (x)
+// CHECK: a#0 <-> func.region0#1: NoAlias
// pointer_dummy's box cannot alias with raw reference to f32 (x)
// CHECK: func.region0#0 <-> func.region0#1: NoAlias
@@ -46,7 +46,7 @@ func.func private @_QPtest2(!fir.ref<f32>)
// -----
-// A composite with a pointer component may alias with a dummy
+// A composite with a pointer component does not alias with a dummy
// argument of composite type with a pointer component:
// module m
// type t
@@ -63,7 +63,7 @@ func.func private @_QPtest2(!fir.ref<f32>)
// end module m
// CHECK-LABEL: Testing : "_QMmPtest"
-// CHECK: a#0 <-> func.region0#0: MayAlias
+// CHECK: a#0 <-> func.region0#0: NoAlias
fir.global @_QMmEa : !fir.type<_QMmTt{pointer_component:!fir.box<!fir.ptr<f32>>}> {
%0 = fir.undefined !fir.type<_QMmTt{pointer_component:!fir.box<!fir.ptr<f32>>}>
@@ -88,7 +88,7 @@ func.func private @_QPtest2(!fir.ref<f32>)
// -----
// Two dummy arguments of composite type with a pointer component
-// may alias each other:
+// do not alias each other:
// module m
// type t
// real, pointer :: pointer_component
@@ -103,7 +103,7 @@ func.func private @_QPtest2(!fir.ref<f32>)
// end module m
// CHECK-LABEL: Testing : "_QMmPtest"
-// CHECK: func.region0#0 <-> func.region0#1: MayAlias
+// CHECK: func.region0#0 <-> func.region0#1: NoAlias
func.func @_QMmPtest(%arg0: !fir.ref<!fir.type<_QMmTt{pointer_component:!fir.box<!fir.ptr<f32>>}>> {fir.bindc_name = "a"}, %arg1: !fir.ref<!fir.type<_QMmTt{pointer_component:!fir.box<!fir.ptr<f32>>}>> {fir.bindc_name = "b"}, %arg2: !fir.ref<f32> {fir.bindc_name = "x", fir.target}) attributes {test.ptr = "func"} {
%0 = fir.field_index pointer_component, !fir.type<_QMmTt{pointer_component:!fir.box<!fir.ptr<f32>>}>
@@ -137,8 +137,7 @@ func.func private @_QPtest2(!fir.ref<f32>)
// end module m
// CHECK-LABEL: Testing : "_QMmPtest"
-// FIXME: MayAlias must be NoAlias
-// CHECK: func.region0#0 <-> func.region0#1: MayAlias
+// CHECK: func.region0#0 <-> func.region0#1: NoAlias
func.func @_QMmPtest(%arg0: !fir.ref<!fir.type<_QMmTt{allocatable_component:!fir.box<!fir.heap<f32>>}>> {fir.bindc_name = "a"}, %arg1: !fir.ref<!fir.type<_QMmTt{allocatable_component:!fir.box<!fir.heap<f32>>}>> {fir.bindc_name = "b"}) attributes {test.ptr = "func"} {
%0 = fir.field_index allocatable_component, !fir.type<_QMmTt{allocatable_component:!fir.box<!fir.heap<f32>>}>
diff --git a/flang/test/Analysis/AliasAnalysis/alias-analysis-9.fir b/flang/test/Analysis/AliasAnalysis/alias-analysis-9.fir
index df24a6d32aa59..67ea4d20caa60 100644
--- a/flang/test/Analysis/AliasAnalysis/alias-analysis-9.fir
+++ b/flang/test/Analysis/AliasAnalysis/alias-analysis-9.fir
@@ -17,13 +17,13 @@
// end module
// CHECK-LABEL: Testing : "_QMmPfoo"
-// TODO: x and y are non pointer, non target argument and therefore do not alias.
-// CHECK-DAG: x#0 <-> y#0: MayAlias
+// x and y are non pointer, non target argument and therefore do not alias.
+// CHECK-DAG: x#0 <-> y#0: NoAlias
-// TODO: y is not a pointer object and therefore does not alias with the x%next component.
-// Also assigning x to y would not modify x.next
-// CHECK-DAG: y#0 <-> xnext1#0: MayAlias
-// CHECK-DAG: y#0 <-> xnext2#0: MayAlias
+// y is not a pointer object and therefore does not alias with the x%next
+// component. Also assigning x to y would not modify x.next
+// CHECK-DAG: y#0 <-> xnext1#0: NoAlias
+// CHECK-DAG: y#0 <-> xnext2#0: NoAlias
// We need to catch the fact that assigning y to x will modify xnext.
// The only side-effect between the 2 loads of x.next is the assignment to x,
>From 9f6d2a7add52dcd3fe51d7376be91b1f3e9b7646 Mon Sep 17 00:00:00 2001
From: "Joel E. Denny" <jdenny.ornl at gmail.com>
Date: Thu, 30 May 2024 15:09:54 -0400
Subject: [PATCH 2/9] WIP: Fix case of ptr dummy arg vs. ptr component
---
.../lib/Optimizer/Analysis/AliasAnalysis.cpp | 41 ++++++++++++++++++-
.../AliasAnalysis/alias-analysis-3.fir | 4 +-
2 files changed, 41 insertions(+), 4 deletions(-)
diff --git a/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp b/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp
index 571b78dc64aa5..9d6640bf181ec 100644
--- a/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp
+++ b/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp
@@ -145,7 +145,7 @@ AliasResult AliasAnalysis::alias(Value lhs, Value rhs) {
((lhsSrc.approximateSource && !lhsSrc.isData() && !rhsSrc.approximateSource) ||
(rhsSrc.approximateSource && !rhsSrc.isData() && !lhsSrc.approximateSource))) {
LLVM_DEBUG(llvm::dbgs()
- << " aliasing between composite and pointer component\n");
+ << " aliasing between composite and non-data component\n");
return AliasResult::MayAlias;
}
@@ -185,13 +185,50 @@ AliasResult AliasAnalysis::alias(Value lhs, Value rhs) {
src2->attributes.set(Attribute::Target);
}
- // Dummy TARGET/POINTER argument may alias with a global TARGET/POINTER.
+ // Two TARGET/POINTERs may alias.
if (src1->isTargetOrPointer() && src2->isTargetOrPointer() &&
src1->isData() == src2->isData()) {
LLVM_DEBUG(llvm::dbgs() << " aliasing because of target or pointer\n");
return AliasResult::MayAlias;
}
+ // A pointer dummy arg may alias a global composite with a pointer component.
+ //
+ // module m
+ // type t
+ // real, pointer :: p
+ // end type
+ // type(t) :: a
+ // type(t) :: b
+ // contains
+ // subroutine test(p)
+ // real, pointer :: p
+ // p = 42
+ // a = b
+ // print *, p
+ // end subroutine
+ // end module
+ // program
+ // use m
+ // real, target :: x1 = 1
+ // real, target :: x2 = 2
+ // a%p => x1
+ // b%p => x2
+ // call test(a%p)
+ // end
+ //
+ // The dummy argument p is an alias for a%p, even for the purposes of pointer
+ // association during the assignment a = b. Thus, the program should print 2.
+ if (src1->kind == SourceKind::Global &&
+ src1->isRecordWithPointerComponent() &&
+ src2->kind == SourceKind::Argument &&
+ src2->attributes.test(Attribute::Pointer)) {
+ LLVM_DEBUG(llvm::dbgs()
+ << " aliasing because of pointer arg and global composite with "
+ << "pointer component\n");
+ return AliasResult::MayAlias;
+ }
+
return AliasResult::NoAlias;
}
diff --git a/flang/test/Analysis/AliasAnalysis/alias-analysis-3.fir b/flang/test/Analysis/AliasAnalysis/alias-analysis-3.fir
index 2bf326f2d2af2..eab438576c2bc 100644
--- a/flang/test/Analysis/AliasAnalysis/alias-analysis-3.fir
+++ b/flang/test/Analysis/AliasAnalysis/alias-analysis-3.fir
@@ -16,9 +16,9 @@
// end subroutine test
// end module m
-// A composite with a pointer component does not alias with a dummy pointer
+// A composite with a pointer component may alias with a dummy pointer
// CHECK-LABEL: Testing : "_QMmPtest
-// CHECK: a#0 <-> func.region0#0: NoAlias
+// CHECK: a#0 <-> func.region0#0: MayAlias
// a's box cannot alias with raw reference to f32 (x)
// CHECK: a#0 <-> func.region0#1: NoAlias
>From 78fc160208cb3bd0d1d2a1be418de50ba1ef2a63 Mon Sep 17 00:00:00 2001
From: "Joel E. Denny" <jdenny.ornl at gmail.com>
Date: Wed, 5 Jun 2024 12:10:19 -0400
Subject: [PATCH 3/9] Fix logic in various ways, and add some tests
For the static case (when source values are the same):
- As discussed in this PR with Renaud Kauffmann, rely on types and
`!isData` instead of `approximateSource`, which doesn't necessarily
indicate a component.
- Improve comments to document effect on allocatables and some
remaining limitations.
For the dynamic case:
- For the composite, as discussed in the RFC, don't restrict it to a
global. It might be an argument. Just exclude locals, which cannot
be aliased by a pointer dummy arg.
- For the pointer, make sure it's the address of the pointer
(`!isData`) not the address in the pointer.
- For the pointer, make sure it's a dummy argument not a component of
a composite dummy argument.
For both cases, for the composite, call `isRecordWithPointerComponent`
on the value (`lhs` or `rhs`) not on its source. Otherwise, we can
mistake a separate component for a composite.
Fix `getSource` to record pointer attributes for `DesignateOp`.
Otherwise, we miss MayAlias for pointer components vs. other pointers.
Before the changes in this PR, `isRecordWithPointerComponent` returned
true on the source of a pointer component, and that was enough to
return MayAlias for it vs. another pointer.
Extend tests, including coverage of all fixes above.
---
.../flang/Optimizer/Analysis/AliasAnalysis.h | 9 +-
.../lib/Optimizer/Analysis/AliasAnalysis.cpp | 81 +++++---
.../AliasAnalysis/alias-analysis-9.fir | 180 +++++++++++++++++-
3 files changed, 238 insertions(+), 32 deletions(-)
diff --git a/flang/include/flang/Optimizer/Analysis/AliasAnalysis.h b/flang/include/flang/Optimizer/Analysis/AliasAnalysis.h
index 40fd1705115a0..a3356052a31dd 100644
--- a/flang/include/flang/Optimizer/Analysis/AliasAnalysis.h
+++ b/flang/include/flang/Optimizer/Analysis/AliasAnalysis.h
@@ -142,17 +142,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 9d6640bf181ec..9a489c558950b 100644
--- a/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp
+++ b/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp
@@ -70,6 +70,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)
@@ -96,14 +104,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) {
auto lhsSrc = getSource(lhs);
auto rhsSrc = getSource(rhs);
@@ -126,14 +126,6 @@ AliasResult AliasAnalysis::alias(Value lhs, Value rhs) {
// either source is approximate. Approximate sources are for parts of the
// origin, but we don't have info here on which parts and whether they
// overlap, so we normally return MayAlias in that case.
- //
- // There is an exceptional case: The origins might compare unequal because
- // only one has !isData(). If that source is approximate and the other is
- // not, then the former is the source for the address *of* a pointer
- // component in a composite, and the latter is for the address of that
- // composite. As for the address of any composite vs. the address of one of
- // its components, a store to one can affect a load from the other, so the
- // result is MayAlias.
if (lhsSrc.origin == rhsSrc.origin) {
LLVM_DEBUG(llvm::dbgs()
<< " aliasing because same source kind and origin\n");
@@ -141,11 +133,32 @@ 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 &&
- ((lhsSrc.approximateSource && !lhsSrc.isData() && !rhsSrc.approximateSource) ||
- (rhsSrc.approximateSource && !rhsSrc.isData() && !lhsSrc.approximateSource))) {
+ ((Source::isRecordWithPointerComponent(lhs.getType()) &&
+ !rhsSrc.isData()) ||
+ (Source::isRecordWithPointerComponent(rhs.getType()) &&
+ !lhsSrc.isData()))) {
LLVM_DEBUG(llvm::dbgs()
- << " aliasing between composite and non-data component\n");
+ << " aliasing between composite and non-data component with "
+ << "same source kind and origin value\n");
return AliasResult::MayAlias;
}
@@ -157,12 +170,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 &&
@@ -192,7 +210,10 @@ AliasResult AliasAnalysis::alias(Value lhs, Value rhs) {
return AliasResult::MayAlias;
}
- // A pointer dummy arg may alias a global composite with a pointer component.
+ // 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
@@ -219,13 +240,19 @@ AliasResult AliasAnalysis::alias(Value lhs, Value rhs) {
//
// The dummy argument p is an alias for a%p, even for the purposes of pointer
// association during the assignment a = b. Thus, the program should print 2.
- if (src1->kind == SourceKind::Global &&
- src1->isRecordWithPointerComponent() &&
- src2->kind == SourceKind::Argument &&
- src2->attributes.test(Attribute::Pointer)) {
+ 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 because of pointer arg and global composite with "
- << "pointer component\n");
+ << " aliasing between pointer arg and composite with pointer "
+ << "component\n");
return AliasResult::MayAlias;
}
@@ -395,6 +422,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-9.fir b/flang/test/Analysis/AliasAnalysis/alias-analysis-9.fir
index 67ea4d20caa60..f5a2903181d0f 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
@@ -57,3 +65,173 @@ func.func @_QMmPfoo(%arg0: !fir.ref<!fir.type<_QMmTt{next:!fir.box<!fir.ptr<!fir
hlfir.assign %15 to %3#0 : i32, !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
+
+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 case 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 here.
+//
+// CHECK-DAG: argp#0 <-> loc#0: NoAlias
+// CHECK-DAG: argp#0 <-> loc%p#0: MayAlias
+// CHECK-DAG: argp#0 <-> loc%i#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: arga#0 <-> loc#0: NoAlias
+// CHECK-DAG: arga#0 <-> loc%p#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
+}
>From 492efb3c5670dc9cd9513d7ce7691cd4654358c6 Mon Sep 17 00:00:00 2001
From: "Joel E. Denny" <jdenny.ornl at gmail.com>
Date: Tue, 11 Jun 2024 18:05:44 -0400
Subject: [PATCH 4/9] Check x%next vs. y%next
---
flang/test/Analysis/AliasAnalysis/alias-analysis-9.fir | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/flang/test/Analysis/AliasAnalysis/alias-analysis-9.fir b/flang/test/Analysis/AliasAnalysis/alias-analysis-9.fir
index f5a2903181d0f..a5380bde9d108 100644
--- a/flang/test/Analysis/AliasAnalysis/alias-analysis-9.fir
+++ b/flang/test/Analysis/AliasAnalysis/alias-analysis-9.fir
@@ -43,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>)
@@ -63,6 +69,7 @@ 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
}
>From ad0438c9d03efb24fd327ef70b8b4b1a60f17637 Mon Sep 17 00:00:00 2001
From: "Joel E. Denny" <jdenny.ornl at gmail.com>
Date: Thu, 13 Jun 2024 17:51:54 -0400
Subject: [PATCH 5/9] Drop accidental -debug from fir-opt in test
However, FileCheck directives then fail. fir-opt's stdout (MLIR
output) and stderr (diagnostics) are jumbled together, and somehow
-debug changes the jumble sufficiently for FileCheck directives to
pass. We don't actually need stdout, so send it to /dev/null. That
makes the output easier to read anyway when debugging.
---
flang/test/Analysis/AliasAnalysis/alias-analysis-9.fir | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/flang/test/Analysis/AliasAnalysis/alias-analysis-9.fir b/flang/test/Analysis/AliasAnalysis/alias-analysis-9.fir
index 5753301f975c5..0042d015b060b 100644
--- a/flang/test/Analysis/AliasAnalysis/alias-analysis-9.fir
+++ b/flang/test/Analysis/AliasAnalysis/alias-analysis-9.fir
@@ -1,4 +1,4 @@
-// RUN: fir-opt -debug %s -split-input-file \
+// RUN: fir-opt %s -split-input-file -o /dev/null \
// RUN: -pass-pipeline='builtin.module(func.func(test-fir-alias-analysis))' \
// RUN: 2>&1 | FileCheck -match-full-lines %s
>From 1e5fdd49f4c8558f5181b3bdb2d38002e0b34630 Mon Sep 17 00:00:00 2001
From: "Joel E. Denny" <jdenny.ornl at gmail.com>
Date: Thu, 13 Jun 2024 17:55:35 -0400
Subject: [PATCH 6/9] Relocate some functions as requested by reviewer
---
.../flang/Optimizer/Analysis/AliasAnalysis.h | 17 +++++-----
.../lib/Optimizer/Analysis/AliasAnalysis.cpp | 31 +++++++++----------
2 files changed, 23 insertions(+), 25 deletions(-)
diff --git a/flang/include/flang/Optimizer/Analysis/AliasAnalysis.h b/flang/include/flang/Optimizer/Analysis/AliasAnalysis.h
index 4963d39c52bdd..9a70b7fbfad2b 100644
--- a/flang/include/flang/Optimizer/Analysis/AliasAnalysis.h
+++ b/flang/include/flang/Optimizer/Analysis/AliasAnalysis.h
@@ -158,14 +158,6 @@ struct AliasAnalysis {
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);
};
friend llvm::raw_ostream &operator<<(llvm::raw_ostream &os,
@@ -182,6 +174,15 @@ struct AliasAnalysis {
/// will stop at [hl]fir.declare if it represents a dummy
/// argument declaration (i.e. it has the dummy_scope operand).
Source getSource(mlir::Value, bool getInstantiationPoint = false);
+
+private:
+ /// 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);
};
inline bool operator==(const AliasAnalysis::Source::SourceOrigin &lhs,
diff --git a/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp b/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp
index 87389a848b9bf..3ebe65d515e19 100644
--- a/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp
+++ b/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp
@@ -60,7 +60,7 @@ void AliasAnalysis::Source::print(llvm::raw_ostream &os) const {
attributes.Dump(os, EnumToString);
}
-bool AliasAnalysis::Source::isRecordWithPointerComponent(mlir::Type ty) {
+bool AliasAnalysis::isRecordWithPointerComponent(mlir::Type ty) {
auto eleTy = fir::dyn_cast_ptrEleTy(ty);
if (!eleTy)
return false;
@@ -68,7 +68,7 @@ bool AliasAnalysis::Source::isRecordWithPointerComponent(mlir::Type ty) {
return mlir::isa<fir::RecordType>(eleTy);
}
-bool AliasAnalysis::Source::isPointerReference(mlir::Type ty) {
+bool AliasAnalysis::isPointerReference(mlir::Type ty) {
auto eleTy = fir::dyn_cast_ptrEleTy(ty);
if (!eleTy)
return false;
@@ -139,16 +139,13 @@ AliasResult AliasAnalysis::alias(Value lhs, Value rhs) {
// 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.
+ // 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 &&
- ((Source::isRecordWithPointerComponent(lhs.getType()) &&
- !rhsSrc.isData()) ||
- (Source::isRecordWithPointerComponent(rhs.getType()) &&
- !lhsSrc.isData()))) {
+ ((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");
@@ -233,16 +230,16 @@ AliasResult AliasAnalysis::alias(Value lhs, Value rhs) {
//
// 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()) &&
+ if ((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()) &&
+ !isRecordWithPointerComponent(src2->valueType)) ||
+ (isRecordWithPointerComponent(val2->getType()) &&
src2->kind != SourceKind::Allocate &&
src1->kind == SourceKind::Argument &&
src1->attributes.test(Attribute::Pointer) && !src1->isData() &&
- !Source::isRecordWithPointerComponent(src1->valueType))) {
+ !isRecordWithPointerComponent(src1->valueType))) {
LLVM_DEBUG(llvm::dbgs()
<< " aliasing between pointer arg and composite with pointer "
<< "component\n");
@@ -382,7 +379,7 @@ AliasAnalysis::Source AliasAnalysis::getSource(mlir::Value v,
// TODO: Take followBoxData into account when setting the pointer
// attribute
- if (Source::isPointerReference(ty))
+ if (isPointerReference(ty))
attributes.set(Attribute::Pointer);
global = llvm::cast<fir::AddrOfOp>(op).getSymbol();
breakFromLoop = true;
@@ -461,7 +458,7 @@ AliasAnalysis::Source AliasAnalysis::getSource(mlir::Value v,
if (fir::valueHasFirAttribute(v, fir::getTargetAttrName()))
attributes.set(Attribute::Target);
- if (Source::isPointerReference(ty))
+ if (isPointerReference(ty))
attributes.set(Attribute::Pointer);
}
>From 3e48239f9a5854693cec0e0d5ef011415c0fa6f7 Mon Sep 17 00:00:00 2001
From: "Joel E. Denny" <jdenny.ornl at gmail.com>
Date: Wed, 19 Jun 2024 10:50:24 -0400
Subject: [PATCH 7/9] Value -> mlir::Value
---
flang/lib/Optimizer/Analysis/AliasAnalysis.cpp | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp b/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp
index 3ebe65d515e19..c67dae29ffb03 100644
--- a/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp
+++ b/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp
@@ -94,7 +94,7 @@ bool AliasAnalysis::Source::isBoxData() const {
origin.isData;
}
-AliasResult AliasAnalysis::alias(Value lhs, Value rhs) {
+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
// not recognize non-aliasing entities.
@@ -160,7 +160,7 @@ AliasResult AliasAnalysis::alias(Value lhs, Value rhs) {
}
Source *src1, *src2;
- Value *val1, *val2;
+ mlir::Value *val1, *val2;
if (lhsSrc.kind < rhsSrc.kind) {
src1 = &lhsSrc;
src2 = &rhsSrc;
>From bec039937832bfebdadb8d8afe9ebf0377ceace3 Mon Sep 17 00:00:00 2001
From: "Joel E. Denny" <jdenny.ornl at gmail.com>
Date: Wed, 19 Jun 2024 18:35:18 -0400
Subject: [PATCH 8/9] Fix and test HostAssoc case
As discussed in review.
---
.../lib/Optimizer/Analysis/AliasAnalysis.cpp | 19 +++-
.../AliasAnalysis/alias-analysis-9.fir | 105 ++++++++++++++++++
2 files changed, 122 insertions(+), 2 deletions(-)
diff --git a/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp b/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp
index c67dae29ffb03..2330b816acf65 100644
--- a/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp
+++ b/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp
@@ -111,6 +111,7 @@ AliasResult AliasAnalysis::alias(mlir::Value lhs, mlir::Value rhs) {
// it aliases with everything
if (lhsSrc.kind >= SourceKind::Indirect ||
rhsSrc.kind >= SourceKind::Indirect) {
+ LLVM_DEBUG(llvm::dbgs() << " aliasing because of indirect access\n");
return AliasResult::MayAlias;
}
@@ -230,14 +231,28 @@ AliasResult AliasAnalysis::alias(mlir::Value lhs, mlir::Value rhs) {
//
// 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 ((isRecordWithPointerComponent(val1->getType()) &&
src1->kind != SourceKind::Allocate &&
- src2->kind == SourceKind::Argument &&
+ src2->kind != SourceKind::Allocate && src2->kind != SourceKind::Global &&
src2->attributes.test(Attribute::Pointer) && !src2->isData() &&
!isRecordWithPointerComponent(src2->valueType)) ||
(isRecordWithPointerComponent(val2->getType()) &&
src2->kind != SourceKind::Allocate &&
- src1->kind == SourceKind::Argument &&
+ src1->kind != SourceKind::Allocate && src1->kind != SourceKind::Global &&
src1->attributes.test(Attribute::Pointer) && !src1->isData() &&
!isRecordWithPointerComponent(src1->valueType))) {
LLVM_DEBUG(llvm::dbgs()
diff --git a/flang/test/Analysis/AliasAnalysis/alias-analysis-9.fir b/flang/test/Analysis/AliasAnalysis/alias-analysis-9.fir
index 0042d015b060b..254ce3ff75dc0 100644
--- a/flang/test/Analysis/AliasAnalysis/alias-analysis-9.fir
+++ b/flang/test/Analysis/AliasAnalysis/alias-analysis-9.fir
@@ -293,3 +293,108 @@ func.func @_QMmPtest(%arg0: !fir.ref<!fir.box<!fir.ptr<i32>>> {fir.bindc_name =
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
+// TODO: Shouldn't these three 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: arga#0 <-> arg#0: NoAlias
+// TODO: Shouldn't this be NoAlias? However, arga is treated like a target
+// because it's HostAssoc and arg is Argument, and arg%p is treated like a
+// pointer.
+// CHECK-DAG: arga#0 <-> arg%p#0: MayAlias
+
+// 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
+// TODO: Shouldn't these three 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: 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 case 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 here.
+//
+// CHECK-DAG: argp#0 <-> loc#0: NoAlias
+// CHECK-DAG: argp#0 <-> loc%p#0: MayAlias
+// CHECK-DAG: argp#0 <-> loc%i#0: NoAlias
+// TODO: Shouldn't these three 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: arga#0 <-> loc#0: NoAlias
+// CHECK-DAG: arga#0 <-> loc%p#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
+}
>From 776a17dbaaae16507baafdd5d0019c2a13db8150 Mon Sep 17 00:00:00 2001
From: "Joel E. Denny" <jdenny.ornl at gmail.com>
Date: Thu, 20 Jun 2024 11:55:49 -0400
Subject: [PATCH 9/9] Fix and test after convert-hlfir-to-fir
In particular, after hlfir.designate becomes fir.coordinate_of.
---
.../lib/Optimizer/Analysis/AliasAnalysis.cpp | 2 +
.../AliasAnalysis/alias-analysis-9.fir | 283 +++++++++++++++++-
2 files changed, 269 insertions(+), 16 deletions(-)
diff --git a/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp b/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp
index 2330b816acf65..30d66e9a799e8 100644
--- a/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp
+++ b/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp
@@ -353,6 +353,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()))
diff --git a/flang/test/Analysis/AliasAnalysis/alias-analysis-9.fir b/flang/test/Analysis/AliasAnalysis/alias-analysis-9.fir
index 254ce3ff75dc0..ca496d91a1ced 100644
--- a/flang/test/Analysis/AliasAnalysis/alias-analysis-9.fir
+++ b/flang/test/Analysis/AliasAnalysis/alias-analysis-9.fir
@@ -1,11 +1,14 @@
-// RUN: fir-opt %s -split-input-file -o /dev/null \
+// 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 difference 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
-// 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?
@@ -27,27 +30,34 @@
// CHECK-LABEL: Testing : "_QMmPfoo"
// 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
// 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
-// TODO: This should be NoAlias. However, AliasAnalysis currently
+// TODO: These 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
+// CHECK-DAG: xnext1.fir#0 <-> ynext.fir#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"}
@@ -73,11 +83,51 @@ func.func @_QMmPfoo(%arg0: !fir.ref<!fir.type<_QMmTt{next:!fir.box<!fir.ptr<!fir
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
+}
+
// -----
// 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}>>)
@@ -92,6 +142,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
@@ -107,6 +171,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>>>}>>)
@@ -124,6 +189,30 @@ func.func @_QMmPfoo3(%arg0: !fir.ref<!fir.type<_QMmTta{array:!fir.box<!fir.ptr<!
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
@@ -144,6 +233,7 @@ func.func @_QMmPfoo3(%arg0: !fir.ref<!fir.type<_QMmTta{array:!fir.box<!fir.ptr<!
// 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>>}>>
@@ -152,6 +242,14 @@ func.func @_QMmPtest() {
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.
@@ -177,6 +275,8 @@ func.func @_QMmPtest() {
// 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 different components of the same composite do not alias.
//
@@ -191,6 +291,9 @@ func.func @_QMmPtest() {
// 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"}
@@ -202,6 +305,20 @@ func.func @_QMmPtest() {
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.
@@ -231,28 +348,50 @@ func.func @_QMmPtest() {
// 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.
//
-// TODO: The argp vs. loc%p case should be NoAlias. However, AliasAnalysis
+// TODO: The argp vs. loc%p cases 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 here.
@@ -260,11 +399,21 @@ func.func @_QMmPtest() {
// CHECK-DAG: argp#0 <-> loc#0: NoAlias
// CHECK-DAG: argp#0 <-> loc%p#0: MayAlias
// 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: MayAlias
+// 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}>
@@ -294,6 +443,38 @@ func.func @_QMmPtest(%arg0: !fir.ref<!fir.box<!fir.ptr<i32>>> {fir.bindc_name =
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.
@@ -321,31 +502,53 @@ func.func @_QMmPtest(%arg0: !fir.ref<!fir.box<!fir.ptr<i32>>> {fir.bindc_name =
// 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
-// TODO: Shouldn't these three be NoAlias? However, argp.tgt is currently
-// handled as Indirect.
+// 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
+//
+// TODO: Shouldn't the arga vs. arg%p cases be NoAlias? However, arga is
+// treated like a target because it's HostAssoc and arg is Argument, and arg%p
+// is treated like a pointer.
// CHECK-DAG: arga#0 <-> arg#0: NoAlias
-// TODO: Shouldn't this be NoAlias? However, arga is treated like a target
-// because it's HostAssoc and arg is Argument, and arg%p is treated like a
-// pointer.
// CHECK-DAG: arga#0 <-> arg%p#0: MayAlias
+// CHECK-DAG: arga.fir#0 <-> arg.fir#0: NoAlias
+// CHECK-DAG: arga.fir#0 <-> arg%p.fir#0: MayAlias
// 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
-// TODO: Shouldn't these three be NoAlias? However, argp.tgt is currently
-// handled as Indirect.
+// 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.
//
@@ -357,13 +560,23 @@ func.func @_QMmPtest(%arg0: !fir.ref<!fir.box<!fir.ptr<i32>>> {fir.bindc_name =
// CHECK-DAG: argp#0 <-> loc#0: NoAlias
// CHECK-DAG: argp#0 <-> loc%p#0: MayAlias
// CHECK-DAG: argp#0 <-> loc%i#0: NoAlias
-// TODO: Shouldn't these three be NoAlias? However, argp.tgt is currently
-// handled as Indirect.
+// CHECK-DAG: argp.fir#0 <-> loc.fir#0: NoAlias
+// CHECK-DAG: argp.fir#0 <-> loc%p.fir#0: MayAlias
+// 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}>
@@ -398,3 +611,41 @@ func.func private @_QMmFparentPtest(%arg0: !fir.ref<!fir.type<_QMmTt{p:!fir.box<
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
+}
More information about the flang-commits
mailing list