[flang-commits] [flang] [flang] Follow memory source through more operations (PR #66713)
Renaud Kauffmann via flang-commits
flang-commits at lists.llvm.org
Tue Sep 19 09:38:13 PDT 2023
https://github.com/Renaud-K updated https://github.com/llvm/llvm-project/pull/66713
>From af689f061df81073ba227e0b8859d39e3c562c09 Mon Sep 17 00:00:00 2001
From: Renaud-K <rkauffmann at nvidia.com>
Date: Mon, 18 Sep 2023 15:11:35 -0700
Subject: [PATCH 1/2] Follow memory source through more operations
---
.../flang/Optimizer/Analysis/AliasAnalysis.h | 3 +-
.../lib/Optimizer/Analysis/AliasAnalysis.cpp | 112 ++-
.../AliasAnalysis/alias-analysis-2.fir | 30 +-
.../AliasAnalysis/alias-analysis-5.fir | 671 ++++++++++++++++++
.../AliasAnalysis/alias-analysis-6.fir | 24 +
5 files changed, 805 insertions(+), 35 deletions(-)
create mode 100644 flang/test/Analysis/AliasAnalysis/alias-analysis-5.fir
create mode 100644 flang/test/Analysis/AliasAnalysis/alias-analysis-6.fir
diff --git a/flang/include/flang/Optimizer/Analysis/AliasAnalysis.h b/flang/include/flang/Optimizer/Analysis/AliasAnalysis.h
index ddde328f5cb5a4d..e96942abc22f3ee 100644
--- a/flang/include/flang/Optimizer/Analysis/AliasAnalysis.h
+++ b/flang/include/flang/Optimizer/Analysis/AliasAnalysis.h
@@ -20,7 +20,7 @@ namespace fir {
//===----------------------------------------------------------------------===//
// AliasAnalysis
//===----------------------------------------------------------------------===//
-class AliasAnalysis {
+struct AliasAnalysis {
// Structures to describe the memory source of a value.
/// Kind of the memory source referenced by a value.
@@ -81,7 +81,6 @@ class AliasAnalysis {
friend llvm::raw_ostream &operator<<(llvm::raw_ostream &os,
const AliasAnalysis::Source &op);
-public:
/// Given two values, return their aliasing behavior.
mlir::AliasResult alias(mlir::Value lhs, mlir::Value rhs);
diff --git a/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp b/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp
index 767ef2e8fa7dc08..6f8b8b441c5dfe5 100644
--- a/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp
+++ b/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp
@@ -36,6 +36,21 @@ static bool isDummyArgument(mlir::Value v) {
return blockArg.getOwner()->isEntryBlock();
}
+/// Temporary function to skip through all the no op operations
+/// TODO: Generalize support of fir.load
+static mlir::Value getOriginalDef(mlir::Value v) {
+ mlir::Operation *defOp;
+ bool breakFromLoop = false;
+ while (!breakFromLoop && (defOp = v.getDefiningOp())) {
+ llvm::TypeSwitch<Operation *>(defOp)
+ .Case<fir::ConvertOp>([&](fir::ConvertOp op) { v = op.getValue(); })
+ .Case<fir::DeclareOp, hlfir::DeclareOp>(
+ [&](auto op) { v = op.getMemref(); })
+ .Default([&](auto op) { breakFromLoop = true; });
+ }
+ return v;
+}
+
namespace fir {
void AliasAnalysis::Source::print(llvm::raw_ostream &os) const {
@@ -80,12 +95,27 @@ AliasResult AliasAnalysis::alias(Value lhs, Value rhs) {
llvm::dbgs() << " rhsSrc: " << rhsSrc << "\n";
llvm::dbgs() << "\n";);
+ // SourceKind::Unknown is set for the addresses wrapped in a global boxes.
+ // ie: fir.global @_QMpointersEp : !fir.box<!fir.ptr<f32>>
+ // Though nothing is known about them, they would only alias with targets or
+ // pointers
+ bool unknownSourceToNonTargetOrPointer = false;
+ if (lhsSrc.u != rhsSrc.u) {
+ if ((lhsSrc.kind == SourceKind::Unknown && !rhsSrc.isTargetOrPointer()) ||
+ (rhsSrc.kind == SourceKind::Unknown && !lhsSrc.isTargetOrPointer())) {
+ unknownSourceToNonTargetOrPointer = true;
+ }
+ }
+
// Indirect case currently not handled. Conservatively assume
// it aliases with everything
if (lhsSrc.kind == SourceKind::Indirect ||
lhsSrc.kind == SourceKind::Unknown ||
- rhsSrc.kind == SourceKind::Indirect || rhsSrc.kind == SourceKind::Unknown)
- return AliasResult::MayAlias;
+ rhsSrc.kind == SourceKind::Indirect ||
+ rhsSrc.kind == SourceKind::Unknown) {
+ if (!unknownSourceToNonTargetOrPointer)
+ return AliasResult::MayAlias;
+ }
if (lhsSrc.kind == rhsSrc.kind) {
if (lhsSrc.u == rhsSrc.u) {
@@ -103,9 +133,6 @@ AliasResult AliasAnalysis::alias(Value lhs, Value rhs) {
lhsSrc.kind == SourceKind::Global)
return AliasResult::NoAlias;
- assert(lhsSrc.kind == SourceKind::Argument &&
- "unexpected memory source kind");
-
// Dummy TARGET/POINTER arguments may alias.
if (lhsSrc.isTargetOrPointer() && rhsSrc.isTargetOrPointer())
return AliasResult::MayAlias;
@@ -122,7 +149,7 @@ AliasResult AliasAnalysis::alias(Value lhs, Value rhs) {
return AliasResult::NoAlias;
}
- assert(lhsSrc.kind != rhsSrc.kind && "memory source kinds must be the same");
+ assert(lhsSrc.kind != rhsSrc.kind && "memory source kinds must be different");
Source *src1, *src2;
if (lhsSrc.kind < rhsSrc.kind) {
@@ -133,18 +160,6 @@ AliasResult AliasAnalysis::alias(Value lhs, Value rhs) {
src2 = &lhsSrc;
}
- assert(src2->kind <= SourceKind::HostAssoc &&
- "unexpected memory source kind");
- if (src1->kind == SourceKind::Allocate)
- return AliasResult::NoAlias;
-
- assert(((src1->kind == SourceKind::Global &&
- (src2->kind == SourceKind::Argument ||
- src2->kind == SourceKind::HostAssoc)) ||
- (src1->kind == SourceKind::Argument &&
- src2->kind == SourceKind::HostAssoc)) &&
- "unexpected memory source kinds");
-
if (src1->kind == SourceKind::Argument &&
src2->kind == SourceKind::HostAssoc) {
// Treat the host entity as TARGET for the purpose of disambiguating
@@ -229,6 +244,7 @@ AliasAnalysis::Source AliasAnalysis::getSource(mlir::Value v) {
mlir::Type ty;
bool breakFromLoop{false};
bool approximateSource{false};
+ bool followBoxAddr{false};
mlir::SymbolRefAttr global;
Source::Attributes attributes;
while (defOp && !breakFromLoop) {
@@ -244,22 +260,74 @@ AliasAnalysis::Source AliasAnalysis::getSource(mlir::Value v) {
v = op->getOperand(0);
defOp = v.getDefiningOp();
})
+ .Case<fir::BoxAddrOp>([&](auto op) {
+ v = op->getOperand(0);
+ defOp = v.getDefiningOp();
+ if (mlir::isa<fir::BaseBoxType>(v.getType()))
+ followBoxAddr = true;
+ })
+ .Case<fir::ArrayCoorOp, fir::CoordinateOp>([&](auto op) {
+ v = op->getOperand(0);
+ defOp = v.getDefiningOp();
+ if (mlir::isa<fir::BaseBoxType>(v.getType()))
+ followBoxAddr = true;
+ approximateSource = true;
+ })
+ .Case<fir::EmboxOp, fir::ReboxOp>([&](auto op) {
+ if (followBoxAddr) {
+ v = op->getOperand(0);
+ defOp = v.getDefiningOp();
+ } else
+ breakFromLoop = true;
+ })
.Case<fir::LoadOp>([&](auto op) {
- // No further tracking for addresses loaded from memory (e.g. a box)
- // right now.
+ if (followBoxAddr && mlir::isa<fir::BaseBoxType>(op.getType())) {
+ // For now, support the load of an argument or fir.address_of
+ // TODO: generalize to all operations (in particular fir.alloca and
+ // fir.allocmem)
+ auto def = getOriginalDef(op.getMemref());
+ if (isDummyArgument(def) ||
+ def.template getDefiningOp<fir::AddrOfOp>()) {
+ v = def;
+ defOp = v.getDefiningOp();
+ return;
+ }
+ }
+ // No further tracking for addresses loaded from memory for now.
type = SourceKind::Indirect;
breakFromLoop = true;
})
.Case<fir::AddrOfOp>([&](auto op) {
// Address of a global scope object.
- type = SourceKind::Global;
ty = v.getType();
+
+ // When the global is a
+ // fir.global @_QMpointersEp : !fir.box<!fir.ptr<f32>>
+ // or
+ // fir.global @_QMpointersEp : !fir.box<!fir.heap<f32>>
+ //
+ // and when following through the wrapped address, capture
+ // the fact that there is nothing known about it. Therefore setting
+ // the source to unknown.
+ //
+ // When not following the wrapped address, then consider the address
+ // of the box, which has nothing to do with the wrapped address and
+ // lies in the global memory space.
+ if (followBoxAddr &&
+ mlir::isa<fir::BaseBoxType>(fir::unwrapRefType(ty)))
+ type = SourceKind::Unknown;
+ else
+ type = SourceKind::Global;
+
if (fir::valueHasFirAttribute(v,
fir::GlobalOp::getTargetAttrNameStr()))
attributes.set(Attribute::Target);
+ // TODO: Take followBoxAddr into account when setting the pointer
+ // attribute
if (Source::isPointerReference(ty))
attributes.set(Attribute::Pointer);
+
global = llvm::cast<fir::AddrOfOp>(op).getSymbol();
breakFromLoop = true;
})
@@ -278,7 +346,7 @@ AliasAnalysis::Source AliasAnalysis::getSource(mlir::Value v) {
breakFromLoop = true;
return;
}
-
+ // TODO: Look for the fortran attributes present on the operation
// Track further through the operand
v = op.getMemref();
defOp = v.getDefiningOp();
diff --git a/flang/test/Analysis/AliasAnalysis/alias-analysis-2.fir b/flang/test/Analysis/AliasAnalysis/alias-analysis-2.fir
index ca720cf0ec813a5..31459ef21d947c3 100644
--- a/flang/test/Analysis/AliasAnalysis/alias-analysis-2.fir
+++ b/flang/test/Analysis/AliasAnalysis/alias-analysis-2.fir
@@ -11,8 +11,11 @@
// p1.addr and p2.addr could both be wrapped inside boxes
// CHECK-DAG: p1.addr#0 <-> boxp1.addr#0: MayAlias
// CHECK-DAG: p2.addr#0 <-> boxp1.addr#0: MayAlias
-// CHECK-DAG: p1.addr#0 <-> arg2.addr#0: MayAlias
-// CHECK-DAG: p2.addr#0 <-> arg2.addr#0: MayAlias
+
+// TODO: To really see aliasing, we should be looking at a load of p1.addr
+// p1.addr is just a local address holding the address to the data
+// CHECK-DAG: p1.addr#0 <-> arg2.addr#0: NoAlias
+// CHECK-DAG: p2.addr#0 <-> arg2.addr#0: NoAlias
// p1.addr and p2.addr are the result of an allocation
// They cannot physically alias with an argument
@@ -41,7 +44,7 @@
// pointer arguments
// CHECK-DAG: arg2.addr#0 <-> func.region0#0: MayAlias
// CHECK-DAG: arg2.addr#0 <-> func.region0#1: MayAlias
-// CHECK-DAG: arg2.addr#0 <-> func.region0#2: MayAlias
+// CHECK-DAG: arg2.addr#0 <-> func.region0#2: MustAlias
// CHECK-DAG: boxp1.addr#0 <-> arg2.addr#0: MayAlias
func.func @_QFPtest(%arg0: !fir.ref<f32> {fir.bindc_name = "v1", fir.target}, %arg1: !fir.ref<f32> {fir.bindc_name = "v2", fir.target}, %arg2: !fir.ref<!fir.box<!fir.ptr<f32>>> ) attributes {test.ptr = "func"} {
@@ -99,7 +102,7 @@ func.func @_QFPtest(%arg0: !fir.ref<f32> {fir.bindc_name = "v1", fir.target}, %a
// CHECK-DAG: func.region0#0 <-> func.region0#1: MayAlias
// CHECK-DAG: func.region0#0 <-> func.region0#2: MayAlias
-func.func @_QFPtest2(%arg0: !fir.ref<f32> {fir.bindc_name = "v1", fir.target}, %arg1: !fir.ref<!fir.box<!fir.ptr<f32>>>, %arg2: !fir.ref<!fir.ptr<f32>> ) attributes {test.ptr = "func"} {
+func.func @_QFPtest2(%arg0: !fir.ref<f32> {fir.bindc_name = "v1", fir.target}, %arg1: !fir.ref<!fir.box<!fir.ptr<f32>>>, %arg2: !fir.ref<!fir.box<!fir.ptr<f32>>> ) attributes {test.ptr = "func"} {
return
}
@@ -131,9 +134,14 @@ func.func @_QFPtest2(%arg0: !fir.ref<f32> {fir.bindc_name = "v1", fir.target}, %
// CHECK-DAG: p#0 <-> func.region0#0: MayAlias
// CHECK-DAG: p#0 <-> func.region0#1: NoAlias
-// FIXME: p and p1 are pointers, they cannot alias with a wrapped address.
-// Only the addresses they wrap could alias with the address wrapped by the box
-// CHECK-DAG: p#0 <-> box.addr#0: MayAlias
+// p could be pointing to var2
+// var2, being a target, could also be passed as argument arg0
+
+// This was the wrong question to ask. We are asking if the address of box _QMpointersEp can
+// alias with the wrapped scalar _QFEvar2. We meant box_addr of _QMpointersEp
+// CHECK-DAG: p#0 <-> box.addr#0: NoAlias
+
+// TODO: Still need to handle more gracefully the difference between !fir.ref<!fir.box<>> and !fir.box<>
// CHECK-DAG: box.addr#0 <-> func.region0#0: MayAlias
// var2, although it is a target, cannot alias with p
@@ -141,14 +149,14 @@ func.func @_QFPtest2(%arg0: !fir.ref<f32> {fir.bindc_name = "v1", fir.target}, %
// CHECK-DAG: var2#0 <-> p#0: NoAlias
// It can alias with p1, if p1 is a pointer component
// CHECK-DAG: var2#0 <-> func.region0#0: MayAlias
-// It can alias with a box.addr
-// CHECK-DAG: var2#0 <-> box.addr#0: MayAlias
+// It is the same as box.addr
+// CHECK-DAG: var2#0 <-> box.addr#0: MustAlias
// A global may not alias with a dummy
// CHECK-DAG: var2#0 <-> func.region0#1: NoAlias
-// FIXME: a pointer may only alias with a target but arg1 is a regular dummy
-// CHECK-DAG: box.addr#0 <-> func.region0#1: MayAlias
+// A pointer may only alias with a target but arg1 is a regular dummy
+// CHECK-DAG: box.addr#0 <-> func.region0#1: NoAlias
// Dummy argument do not alias
// CHECK-DAG: func.region0#0 <-> func.region0#1: NoAlias
diff --git a/flang/test/Analysis/AliasAnalysis/alias-analysis-5.fir b/flang/test/Analysis/AliasAnalysis/alias-analysis-5.fir
new file mode 100644
index 000000000000000..062413858691204
--- /dev/null
+++ b/flang/test/Analysis/AliasAnalysis/alias-analysis-5.fir
@@ -0,0 +1,671 @@
+// Use --mlir-disable-threading so that the AA queries are serialized
+// as well as its diagnostic output.
+// RUN: fir-opt %s -pass-pipeline='builtin.module(func.func(test-fir-alias-analysis))' -split-input-file --mlir-disable-threading 2>&1 | FileCheck %s
+
+// CHECK-LABEL: Testing : "_QPtest1"
+// CHECK: arraya(ii)#0 <-> arrayc(ii)#0: NoAlias
+
+// Generated from
+// subroutine test1(arrayA, arrayB, arrayC, N)
+// integer, dimension(:) :: arrayA, arrayB, arrayC
+// integer N
+// do ii = 1, N
+// arrayC(ii) = arrayB(ii) + arrayA(ii)
+// end do
+// end subroutine
+
+func.func @_QPtest1(%arg0: !fir.box<!fir.array<?xi32>> {fir.bindc_name = "arraya"}, %arg1: !fir.box<!fir.array<?xi32>> {fir.bindc_name = "arrayb"}, %arg2: !fir.box<!fir.array<?xi32>> {fir.bindc_name = "arrayc"}, %arg3: !fir.ref<i32> {fir.bindc_name = "n"}) {
+ %c1 = arith.constant 1 : index
+ %c1_i64 = arith.constant 1 : i64
+ %0 = fir.alloca i32 {bindc_name = "ii", uniq_name = "_QFtest1Eii"}
+ %1 = fir.load %arg3 : !fir.ref<i32>
+ %2 = fir.convert %1 : (i32) -> index
+ %3 = fir.convert %c1 : (index) -> i32
+ %4:2 = fir.do_loop %arg4 = %c1 to %2 step %c1 iter_args(%arg5 = %3) -> (index, i32) {
+ fir.store %arg5 to %0 : !fir.ref<i32>
+ %5 = fir.load %0 : !fir.ref<i32>
+ %6 = fir.convert %5 : (i32) -> i64
+ %7 = arith.subi %6, %c1_i64 : i64
+ %8 = fir.coordinate_of %arg1, %7 : (!fir.box<!fir.array<?xi32>>, i64) -> !fir.ref<i32>
+ %9 = fir.load %8 : !fir.ref<i32>
+ %10 = fir.coordinate_of %arg0, %7 {test.ptr = "arraya(ii)"} : (!fir.box<!fir.array<?xi32>>, i64) -> !fir.ref<i32>
+ %11 = fir.load %10 : !fir.ref<i32>
+ %12 = arith.addi %9, %11 : i32
+ %13 = fir.coordinate_of %arg2, %7 {test.ptr = "arrayc(ii)"} : (!fir.box<!fir.array<?xi32>>, i64) -> !fir.ref<i32>
+ fir.store %12 to %13 : !fir.ref<i32>
+ %14 = arith.addi %arg4, %c1 : index
+ %15 = fir.load %0 : !fir.ref<i32>
+ %16 = arith.addi %15, %3 : i32
+ fir.result %14, %16 : index, i32
+ }
+ fir.store %4#1 to %0 : !fir.ref<i32>
+ return
+}
+
+// -----
+
+// CHECK-LABEL: Testing : "_QPtest3"
+// CHECK: arraya(ii)#0 <-> arrayc(ii)#0: MayAlias
+
+// subroutine test3(arrayA, arrayB, arrayC, N)
+// integer, dimension(:), target :: arrayA
+// integer, dimension(:) :: arrayB
+// integer, dimension(:), pointer :: arrayC
+// do ii = 1, N
+// arrayC(ii) = arrayB(ii) + arrayA(ii)
+// end do
+// end subroutine
+
+func.func @_QPtest3(%arg0: !fir.box<!fir.array<?xi32>> {fir.bindc_name = "arraya", fir.target}, %arg1: !fir.box<!fir.array<?xi32>> {fir.bindc_name = "arrayb"}, %arg2: !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>> {fir.bindc_name = "arrayc"}, %arg3: !fir.ref<i32> {fir.bindc_name = "n"}) {
+ %c1 = arith.constant 1 : index
+ %c0 = arith.constant 0 : index
+ %c1_i64 = arith.constant 1 : i64
+ %0 = fir.alloca i32 {bindc_name = "ii", uniq_name = "_QFtest3Eii"}
+ %1 = fir.load %arg3 : !fir.ref<i32>
+ %2 = fir.convert %1 : (i32) -> index
+ %3 = fir.convert %c1 : (index) -> i32
+ %4:2 = fir.do_loop %arg4 = %c1 to %2 step %c1 iter_args(%arg5 = %3) -> (index, i32) {
+ fir.store %arg5 to %0 : !fir.ref<i32>
+ %5 = fir.load %0 : !fir.ref<i32>
+ %6 = fir.convert %5 : (i32) -> i64
+ %7 = arith.subi %6, %c1_i64 : i64
+ %8 = fir.coordinate_of %arg1, %7 : (!fir.box<!fir.array<?xi32>>, i64) -> !fir.ref<i32>
+ %9 = fir.load %8 : !fir.ref<i32>
+ %10 = fir.coordinate_of %arg0, %7 {test.ptr = "arraya(ii)"} : (!fir.box<!fir.array<?xi32>>, i64) -> !fir.ref<i32>
+ %11 = fir.load %10 : !fir.ref<i32>
+ %12 = arith.addi %9, %11 : i32
+ %13 = fir.load %arg2 : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>
+ %14:3 = fir.box_dims %13, %c0 : (!fir.box<!fir.ptr<!fir.array<?xi32>>>, index) -> (index, index, index)
+ %15 = fir.convert %14#0 : (index) -> i64
+ %16 = arith.subi %6, %15 : i64
+ %17 = fir.coordinate_of %13, %16 {test.ptr = "arrayc(ii)"} : (!fir.box<!fir.ptr<!fir.array<?xi32>>>, i64) -> !fir.ref<i32>
+ fir.store %12 to %17 : !fir.ref<i32>
+ %18 = arith.addi %arg4, %c1 : index
+ %19 = fir.load %0 : !fir.ref<i32>
+ %20 = arith.addi %19, %3 : i32
+ fir.result %18, %20 : index, i32
+ }
+ fir.store %4#1 to %0 : !fir.ref<i32>
+ return
+}
+
+// -----
+
+// CHECK-LABEL: Testing : "_QMtest4Ptest"
+// CHECK: arraya(ii)#0 <-> arrayc(ii)#0: NoAlias
+
+// module test4
+// integer, dimension(:), allocatable :: arrayA
+// integer, dimension(:), allocatable :: arrayB
+// integer, dimension(:), allocatable :: arrayC
+// integer :: N
+// contains
+// subroutine test
+// do ii = 1, N
+// arrayC(ii) = arrayB(ii) + arrayA(ii)
+// end do
+// end subroutine
+// endmodule
+
+fir.global @_QMtest4Earraya : !fir.box<!fir.heap<!fir.array<?xi32>>>
+fir.global @_QMtest4Earrayb : !fir.box<!fir.heap<!fir.array<?xi32>>>
+fir.global @_QMtest4Earrayc : !fir.box<!fir.heap<!fir.array<?xi32>>>
+fir.global @_QMtest4En : i32
+
+func.func @_QMtest4Ptest() {
+ %c1 = arith.constant 1 : index
+ %c0 = arith.constant 0 : index
+ %0 = fir.address_of(@_QMtest4Earraya) : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
+ %1 = fir.address_of(@_QMtest4Earrayb) : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
+ %2 = fir.address_of(@_QMtest4Earrayc) : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
+ %3 = fir.address_of(@_QMtest4En) : !fir.ref<i32>
+ %4 = fir.alloca i32 {bindc_name = "ii", uniq_name = "_QMtest4FtestEii"}
+ %5 = fir.load %3 : !fir.ref<i32>
+ %6 = fir.convert %5 : (i32) -> index
+ %7 = fir.convert %c1 : (index) -> i32
+ %8:2 = fir.do_loop %arg0 = %c1 to %6 step %c1 iter_args(%arg1 = %7) -> (index, i32) {
+ fir.store %arg1 to %4 : !fir.ref<i32>
+ %9 = fir.load %1 : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
+ %10:3 = fir.box_dims %9, %c0 : (!fir.box<!fir.heap<!fir.array<?xi32>>>, index) -> (index, index, index)
+ %11 = fir.box_addr %9 : (!fir.box<!fir.heap<!fir.array<?xi32>>>) -> !fir.heap<!fir.array<?xi32>>
+ %12 = fir.load %4 : !fir.ref<i32>
+ %13 = fir.convert %12 : (i32) -> i64
+ %14 = fir.convert %10#0 : (index) -> i64
+ %15 = arith.subi %13, %14 : i64
+ %16 = fir.coordinate_of %11, %15 : (!fir.heap<!fir.array<?xi32>>, i64) -> !fir.ref<i32>
+ %17 = fir.load %16 : !fir.ref<i32>
+ %18 = fir.load %0 : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
+ %19:3 = fir.box_dims %18, %c0 : (!fir.box<!fir.heap<!fir.array<?xi32>>>, index) -> (index, index, index)
+ %20 = fir.box_addr %18 : (!fir.box<!fir.heap<!fir.array<?xi32>>>) -> !fir.heap<!fir.array<?xi32>>
+ %21 = fir.convert %19#0 : (index) -> i64
+ %22 = arith.subi %13, %21 : i64
+ %23 = fir.coordinate_of %20, %22 {test.ptr = "arraya(ii)"} : (!fir.heap<!fir.array<?xi32>>, i64) -> !fir.ref<i32>
+ %24 = fir.load %23 : !fir.ref<i32>
+ %25 = arith.addi %17, %24 : i32
+ %26 = fir.load %2 : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
+ %27:3 = fir.box_dims %26, %c0 : (!fir.box<!fir.heap<!fir.array<?xi32>>>, index) -> (index, index, index)
+ %28 = fir.box_addr %26 : (!fir.box<!fir.heap<!fir.array<?xi32>>>) -> !fir.heap<!fir.array<?xi32>>
+ %29 = fir.convert %27#0 : (index) -> i64
+ %30 = arith.subi %13, %29 : i64
+ %31 = fir.coordinate_of %28, %30 {test.ptr = "arrayc(ii)"} : (!fir.heap<!fir.array<?xi32>>, i64) -> !fir.ref<i32>
+ fir.store %25 to %31 : !fir.ref<i32>
+ %32 = arith.addi %arg0, %c1 : index
+ %33 = fir.load %4 : !fir.ref<i32>
+ %34 = arith.addi %33, %7 : i32
+ fir.result %32, %34 : index, i32
+ }
+ fir.store %8#1 to %4 : !fir.ref<i32>
+ return
+}
+
+// -----
+
+// CHECK-LABEL: Testing : "_QMtest5Ptest"
+// CHECK: arraya(ii)#0 <-> arrayc(ii)#0: NoAlias
+
+// module test5
+// integer, dimension(:), allocatable :: arrayA
+// integer, dimension(:), allocatable :: arrayB
+// integer, dimension(:), pointer :: arrayC
+// integer :: N
+// contains
+// subroutine test
+// do ii = 1, N
+// arrayC(ii) = arrayB(ii) + arrayA(ii)
+// end do
+// end subroutine
+// endmodule
+
+fir.global @_QMtest5Earraya : !fir.box<!fir.heap<!fir.array<?xi32>>>
+fir.global @_QMtest5Earrayb : !fir.box<!fir.heap<!fir.array<?xi32>>>
+fir.global @_QMtest5Earrayc : !fir.box<!fir.ptr<!fir.array<?xi32>>>
+fir.global @_QMtest5En : i32
+
+func.func @_QMtest5Ptest() {
+ %c1 = arith.constant 1 : index
+ %c0 = arith.constant 0 : index
+ %0 = fir.address_of(@_QMtest5Earraya) : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
+ %1 = fir.address_of(@_QMtest5Earrayb) : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
+ %2 = fir.address_of(@_QMtest5Earrayc) : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>
+ %3 = fir.address_of(@_QMtest5En) : !fir.ref<i32>
+ %4 = fir.alloca i32 {bindc_name = "ii", uniq_name = "_QMtest5FtestEii"}
+ %5 = fir.load %3 : !fir.ref<i32>
+ %6 = fir.convert %5 : (i32) -> index
+ %7 = fir.convert %c1 : (index) -> i32
+ %8:2 = fir.do_loop %arg0 = %c1 to %6 step %c1 iter_args(%arg1 = %7) -> (index, i32) {
+ fir.store %arg1 to %4 : !fir.ref<i32>
+ %9 = fir.load %1 : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
+ %10:3 = fir.box_dims %9, %c0 : (!fir.box<!fir.heap<!fir.array<?xi32>>>, index) -> (index, index, index)
+ %11 = fir.box_addr %9 : (!fir.box<!fir.heap<!fir.array<?xi32>>>) -> !fir.heap<!fir.array<?xi32>>
+ %12 = fir.load %4 : !fir.ref<i32>
+ %13 = fir.convert %12 : (i32) -> i64
+ %14 = fir.convert %10#0 : (index) -> i64
+ %15 = arith.subi %13, %14 : i64
+ %16 = fir.coordinate_of %11, %15 : (!fir.heap<!fir.array<?xi32>>, i64) -> !fir.ref<i32>
+ %17 = fir.load %16 : !fir.ref<i32>
+ %18 = fir.load %0 : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
+ %19:3 = fir.box_dims %18, %c0 : (!fir.box<!fir.heap<!fir.array<?xi32>>>, index) -> (index, index, index)
+ %20 = fir.box_addr %18 : (!fir.box<!fir.heap<!fir.array<?xi32>>>) -> !fir.heap<!fir.array<?xi32>>
+ %21 = fir.convert %19#0 : (index) -> i64
+ %22 = arith.subi %13, %21 : i64
+ %23 = fir.coordinate_of %20, %22 {test.ptr = "arraya(ii)"} : (!fir.heap<!fir.array<?xi32>>, i64) -> !fir.ref<i32>
+ %24 = fir.load %23 : !fir.ref<i32>
+ %25 = arith.addi %17, %24 : i32
+ %26 = fir.load %2 : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>
+ %27:3 = fir.box_dims %26, %c0 : (!fir.box<!fir.ptr<!fir.array<?xi32>>>, index) -> (index, index, index)
+ %28 = fir.convert %27#0 : (index) -> i64
+ %29 = arith.subi %13, %28 : i64
+ %30 = fir.coordinate_of %26, %29 {test.ptr = "arrayc(ii)"} : (!fir.box<!fir.ptr<!fir.array<?xi32>>>, i64) -> !fir.ref<i32>
+ fir.store %25 to %30 : !fir.ref<i32>
+ %31 = arith.addi %arg0, %c1 : index
+ %32 = fir.load %4 : !fir.ref<i32>
+ %33 = arith.addi %32, %7 : i32
+ fir.result %31, %33 : index, i32
+ }
+ fir.store %8#1 to %4 : !fir.ref<i32>
+ return
+}
+
+// -----
+
+// CHECK-LABEL: Testing : "_QMtest6Ptest"
+// CHECK: arraya(ii)#0 <-> arrayc(ii)#0: MayAlias
+
+// module test6
+// integer, dimension(:), allocatable, target :: arrayA
+// integer, dimension(:), allocatable :: arrayB
+// integer, dimension(:), pointer :: arrayC
+// integer :: N
+// contains
+// subroutine test
+// do ii = 1, N
+// arrayC(ii) = arrayB(ii) + arrayA(ii)
+// end do
+// end subroutine
+// endmodule
+
+fir.global @_QMtest6Earraya target : !fir.box<!fir.heap<!fir.array<?xi32>>>
+fir.global @_QMtest6Earrayb : !fir.box<!fir.heap<!fir.array<?xi32>>>
+fir.global @_QMtest6Earrayc : !fir.box<!fir.ptr<!fir.array<?xi32>>>
+fir.global @_QMtest6En : i32
+
+func.func @_QMtest6Ptest() {
+ %c1 = arith.constant 1 : index
+ %c0 = arith.constant 0 : index
+ %0 = fir.address_of(@_QMtest6Earraya) : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
+ %1 = fir.address_of(@_QMtest6Earrayb) : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
+ %2 = fir.address_of(@_QMtest6Earrayc) : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>
+ %3 = fir.address_of(@_QMtest6En) : !fir.ref<i32>
+ %4 = fir.alloca i32 {bindc_name = "ii", uniq_name = "_QMtest6FtestEii"}
+ %5 = fir.load %3 : !fir.ref<i32>
+ %6 = fir.convert %5 : (i32) -> index
+ %7 = fir.convert %c1 : (index) -> i32
+ %8:2 = fir.do_loop %arg0 = %c1 to %6 step %c1 iter_args(%arg1 = %7) -> (index, i32) {
+ fir.store %arg1 to %4 : !fir.ref<i32>
+ %9 = fir.load %1 : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
+ %10:3 = fir.box_dims %9, %c0 : (!fir.box<!fir.heap<!fir.array<?xi32>>>, index) -> (index, index, index)
+ %11 = fir.box_addr %9 : (!fir.box<!fir.heap<!fir.array<?xi32>>>) -> !fir.heap<!fir.array<?xi32>>
+ %12 = fir.load %4 : !fir.ref<i32>
+ %13 = fir.convert %12 : (i32) -> i64
+ %14 = fir.convert %10#0 : (index) -> i64
+ %15 = arith.subi %13, %14 : i64
+ %16 = fir.coordinate_of %11, %15 : (!fir.heap<!fir.array<?xi32>>, i64) -> !fir.ref<i32>
+ %17 = fir.load %16 : !fir.ref<i32>
+ %18 = fir.load %0 : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
+ %19:3 = fir.box_dims %18, %c0 : (!fir.box<!fir.heap<!fir.array<?xi32>>>, index) -> (index, index, index)
+ %20 = fir.box_addr %18 : (!fir.box<!fir.heap<!fir.array<?xi32>>>) -> !fir.heap<!fir.array<?xi32>>
+ %21 = fir.convert %19#0 : (index) -> i64
+ %22 = arith.subi %13, %21 : i64
+ %23 = fir.coordinate_of %20, %22 {test.ptr = "arraya(ii)"} : (!fir.heap<!fir.array<?xi32>>, i64) -> !fir.ref<i32>
+ %24 = fir.load %23 : !fir.ref<i32>
+ %25 = arith.addi %17, %24 : i32
+ %26 = fir.load %2 : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>
+ %27:3 = fir.box_dims %26, %c0 : (!fir.box<!fir.ptr<!fir.array<?xi32>>>, index) -> (index, index, index)
+ %28 = fir.convert %27#0 : (index) -> i64
+ %29 = arith.subi %13, %28 : i64
+ %30 = fir.coordinate_of %26, %29 {test.ptr = "arrayc(ii)"} : (!fir.box<!fir.ptr<!fir.array<?xi32>>>, i64) -> !fir.ref<i32>
+ fir.store %25 to %30 : !fir.ref<i32>
+ %31 = arith.addi %arg0, %c1 : index
+ %32 = fir.load %4 : !fir.ref<i32>
+ %33 = arith.addi %32, %7 : i32
+ fir.result %31, %33 : index, i32
+ }
+ fir.store %8#1 to %4 : !fir.ref<i32>
+ return
+}
+
+// -----
+
+// CHECK-LABEL: Testing : "_QMtest7Ptest"
+// CHECK: arraya(ii)#0 <-> arrayc(ii)#0: MayAlias
+
+// module test7
+// integer, dimension(1000), target :: arrayA
+// integer, dimension(:), allocatable :: arrayB
+// integer, dimension(:), pointer :: arrayC
+// integer :: N
+// contains
+// subroutine test
+// do ii = 1, N
+// arrayC(ii) = arrayB(ii) + arrayA(ii)
+// end do
+// end subroutine
+// endmodule
+
+fir.global @_QMtest7Earraya target : !fir.array<1000xi32>
+fir.global @_QMtest7Earrayb : !fir.box<!fir.heap<!fir.array<?xi32>>>
+fir.global @_QMtest7Earrayc : !fir.box<!fir.ptr<!fir.array<?xi32>>>
+fir.global @_QMtest7En : i32
+
+func.func @_QMtest7Ptest() {
+ %c1 = arith.constant 1 : index
+ %c1_i64 = arith.constant 1 : i64
+ %c0 = arith.constant 0 : index
+ %0 = fir.address_of(@_QMtest7Earraya) : !fir.ref<!fir.array<1000xi32>>
+ %1 = fir.address_of(@_QMtest7Earrayb) : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
+ %2 = fir.address_of(@_QMtest7Earrayc) : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>
+ %3 = fir.address_of(@_QMtest7En) : !fir.ref<i32>
+ %4 = fir.alloca i32 {bindc_name = "ii", uniq_name = "_QMtest7FtestEii"}
+ %5 = fir.load %3 : !fir.ref<i32>
+ %6 = fir.convert %5 : (i32) -> index
+ %7 = fir.convert %c1 : (index) -> i32
+ %8:2 = fir.do_loop %arg0 = %c1 to %6 step %c1 iter_args(%arg1 = %7) -> (index, i32) {
+ fir.store %arg1 to %4 : !fir.ref<i32>
+ %9 = fir.load %1 : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
+ %10:3 = fir.box_dims %9, %c0 : (!fir.box<!fir.heap<!fir.array<?xi32>>>, index) -> (index, index, index)
+ %11 = fir.box_addr %9 : (!fir.box<!fir.heap<!fir.array<?xi32>>>) -> !fir.heap<!fir.array<?xi32>>
+ %12 = fir.load %4 : !fir.ref<i32>
+ %13 = fir.convert %12 : (i32) -> i64
+ %14 = fir.convert %10#0 : (index) -> i64
+ %15 = arith.subi %13, %14 : i64
+ %16 = fir.coordinate_of %11, %15 : (!fir.heap<!fir.array<?xi32>>, i64) -> !fir.ref<i32>
+ %17 = fir.load %16 : !fir.ref<i32>
+ %18 = arith.subi %13, %c1_i64 : i64
+ %19 = fir.coordinate_of %0, %18 {test.ptr = "arraya(ii)"} : (!fir.ref<!fir.array<1000xi32>>, i64) -> !fir.ref<i32>
+ %20 = fir.load %19 : !fir.ref<i32>
+ %21 = arith.addi %17, %20 : i32
+ %22 = fir.load %2 : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>
+ %23:3 = fir.box_dims %22, %c0 : (!fir.box<!fir.ptr<!fir.array<?xi32>>>, index) -> (index, index, index)
+ %24 = fir.convert %23#0 : (index) -> i64
+ %25 = arith.subi %13, %24 : i64
+ %26 = fir.coordinate_of %22, %25 {test.ptr = "arrayc(ii)"} : (!fir.box<!fir.ptr<!fir.array<?xi32>>>, i64) -> !fir.ref<i32>
+ fir.store %21 to %26 : !fir.ref<i32>
+ %27 = arith.addi %arg0, %c1 : index
+ %28 = fir.load %4 : !fir.ref<i32>
+ %29 = arith.addi %28, %7 : i32
+ fir.result %27, %29 : index, i32
+ }
+ fir.store %8#1 to %4 : !fir.ref<i32>
+ return
+}
+
+// -----
+
+// CHECK-LABEL: Testing : "_QMtest8Ptest"
+// CHECK: arraya(ii)#0 <-> arrayc(ii)#0: NoAlias
+
+// module test8
+// integer, dimension(1000) :: arrayA
+// integer, dimension(:), allocatable :: arrayB
+// integer, dimension(:), pointer :: arrayC
+// integer :: N
+// contains
+// subroutine test
+// do ii = 1, N
+// arrayC(ii) = arrayB(ii) + arrayA(ii)
+// end do
+// end subroutine
+// endmodule
+
+fir.global @_QMtest8Earraya : !fir.array<1000xi32>
+fir.global @_QMtest8Earrayb : !fir.box<!fir.heap<!fir.array<?xi32>>>
+fir.global @_QMtest8Earrayc : !fir.box<!fir.ptr<!fir.array<?xi32>>>
+fir.global @_QMtest8En : i32
+
+func.func @_QMtest8Ptest() {
+ %c1 = arith.constant 1 : index
+ %c1_i64 = arith.constant 1 : i64
+ %c0 = arith.constant 0 : index
+ %0 = fir.address_of(@_QMtest8Earraya) : !fir.ref<!fir.array<1000xi32>>
+ %1 = fir.address_of(@_QMtest8Earrayb) : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
+ %2 = fir.address_of(@_QMtest8Earrayc) : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>
+ %3 = fir.address_of(@_QMtest8En) : !fir.ref<i32>
+ %4 = fir.alloca i32 {bindc_name = "ii", uniq_name = "_QMtest8FtestEii"}
+ %5 = fir.load %3 : !fir.ref<i32>
+ %6 = fir.convert %5 : (i32) -> index
+ %7 = fir.convert %c1 : (index) -> i32
+ %8:2 = fir.do_loop %arg0 = %c1 to %6 step %c1 iter_args(%arg1 = %7) -> (index, i32) {
+ fir.store %arg1 to %4 : !fir.ref<i32>
+ %9 = fir.load %1 : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
+ %10:3 = fir.box_dims %9, %c0 : (!fir.box<!fir.heap<!fir.array<?xi32>>>, index) -> (index, index, index)
+ %11 = fir.box_addr %9 : (!fir.box<!fir.heap<!fir.array<?xi32>>>) -> !fir.heap<!fir.array<?xi32>>
+ %12 = fir.load %4 : !fir.ref<i32>
+ %13 = fir.convert %12 : (i32) -> i64
+ %14 = fir.convert %10#0 : (index) -> i64
+ %15 = arith.subi %13, %14 : i64
+ %16 = fir.coordinate_of %11, %15 : (!fir.heap<!fir.array<?xi32>>, i64) -> !fir.ref<i32>
+ %17 = fir.load %16 : !fir.ref<i32>
+ %18 = arith.subi %13, %c1_i64 : i64
+ %19 = fir.coordinate_of %0, %18 {test.ptr = "arraya(ii)"} : (!fir.ref<!fir.array<1000xi32>>, i64) -> !fir.ref<i32>
+ %20 = fir.load %19 : !fir.ref<i32>
+ %21 = arith.addi %17, %20 : i32
+ %22 = fir.load %2 : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>
+ %23:3 = fir.box_dims %22, %c0 : (!fir.box<!fir.ptr<!fir.array<?xi32>>>, index) -> (index, index, index)
+ %24 = fir.convert %23#0 : (index) -> i64
+ %25 = arith.subi %13, %24 : i64
+ %26 = fir.coordinate_of %22, %25 {test.ptr = "arrayc(ii)"} : (!fir.box<!fir.ptr<!fir.array<?xi32>>>, i64) -> !fir.ref<i32>
+ fir.store %21 to %26 : !fir.ref<i32>
+ %27 = arith.addi %arg0, %c1 : index
+ %28 = fir.load %4 : !fir.ref<i32>
+ %29 = arith.addi %28, %7 : i32
+ fir.result %27, %29 : index, i32
+ }
+ fir.store %8#1 to %4 : !fir.ref<i32>
+ return
+}
+
+// -----
+
+// CHECK-LABEL: Testing : "_QMtest9Ptest"
+// CHECK: arraya(ii)#0 <-> arrayc(ii)#0: NoAlias
+
+// module test9
+// integer, dimension(:), allocatable :: arrayB
+// integer, dimension(:), pointer :: arrayC
+// integer :: N
+// contains
+// subroutine test(arrayA)
+// integer, dimension(:) :: arrayA
+// do ii = 1, N
+// arrayC(ii) = arrayB(ii) + arrayA(ii)
+// end do
+// end subroutine
+// endmodule
+
+fir.global @_QMtest9Earrayb : !fir.box<!fir.heap<!fir.array<?xi32>>>
+fir.global @_QMtest9Earrayc : !fir.box<!fir.ptr<!fir.array<?xi32>>>
+fir.global @_QMtest9En : i32
+
+func.func @_QMtest9Ptest(%arg0: !fir.box<!fir.array<?xi32>> {fir.bindc_name = "arraya"}) {
+ %c1 = arith.constant 1 : index
+ %c1_i64 = arith.constant 1 : i64
+ %c0 = arith.constant 0 : index
+ %0 = fir.address_of(@_QMtest9Earrayb) : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
+ %1 = fir.address_of(@_QMtest9Earrayc) : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>
+ %2 = fir.address_of(@_QMtest9En) : !fir.ref<i32>
+ %3 = fir.alloca i32 {bindc_name = "ii", uniq_name = "_QMtest9FtestEii"}
+ %4 = fir.load %2 : !fir.ref<i32>
+ %5 = fir.convert %4 : (i32) -> index
+ %6 = fir.convert %c1 : (index) -> i32
+ %7:2 = fir.do_loop %arg1 = %c1 to %5 step %c1 iter_args(%arg2 = %6) -> (index, i32) {
+ fir.store %arg2 to %3 : !fir.ref<i32>
+ %8 = fir.load %0 : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
+ %9:3 = fir.box_dims %8, %c0 : (!fir.box<!fir.heap<!fir.array<?xi32>>>, index) -> (index, index, index)
+ %10 = fir.box_addr %8 : (!fir.box<!fir.heap<!fir.array<?xi32>>>) -> !fir.heap<!fir.array<?xi32>>
+ %11 = fir.load %3 : !fir.ref<i32>
+ %12 = fir.convert %11 : (i32) -> i64
+ %13 = fir.convert %9#0 : (index) -> i64
+ %14 = arith.subi %12, %13 : i64
+ %15 = fir.coordinate_of %10, %14 : (!fir.heap<!fir.array<?xi32>>, i64) -> !fir.ref<i32>
+ %16 = fir.load %15 : !fir.ref<i32>
+ %17 = arith.subi %12, %c1_i64 : i64
+ %18 = fir.coordinate_of %arg0, %17 {test.ptr = "arraya(ii)"} : (!fir.box<!fir.array<?xi32>>, i64) -> !fir.ref<i32>
+ %19 = fir.load %18 : !fir.ref<i32>
+ %20 = arith.addi %16, %19 : i32
+ %21 = fir.load %1 : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>
+ %22:3 = fir.box_dims %21, %c0 : (!fir.box<!fir.ptr<!fir.array<?xi32>>>, index) -> (index, index, index)
+ %23 = fir.convert %22#0 : (index) -> i64
+ %24 = arith.subi %12, %23 : i64
+ %25 = fir.coordinate_of %21, %24 {test.ptr = "arrayc(ii)"} : (!fir.box<!fir.ptr<!fir.array<?xi32>>>, i64) -> !fir.ref<i32>
+ fir.store %20 to %25 : !fir.ref<i32>
+ %26 = arith.addi %arg1, %c1 : index
+ %27 = fir.load %3 : !fir.ref<i32>
+ %28 = arith.addi %27, %6 : i32
+ fir.result %26, %28 : index, i32
+ }
+ fir.store %7#1 to %3 : !fir.ref<i32>
+ return
+}
+
+// -----
+
+// CHECK-LABEL: Testing : "_QMtest10Ptest"
+// CHECK: arraya(ii)#0 <-> arrayc(ii)#0: MayAlias
+
+// module test10
+// integer, dimension(:), allocatable :: arrayB
+// integer, dimension(:), pointer :: arrayC
+// integer :: N
+// contains
+// subroutine test(arrayA)
+// integer, dimension(:), target :: arrayA
+// do ii = 1, N
+// arrayC(ii) = arrayB(ii) + arrayA(ii)
+// end do
+// end subroutine
+// endmodule
+
+fir.global @_QMtest10Earrayb : !fir.box<!fir.heap<!fir.array<?xi32>>>
+fir.global @_QMtest10Earrayc : !fir.box<!fir.ptr<!fir.array<?xi32>>>
+fir.global @_QMtest10En : i32
+
+func.func @_QMtest10Ptest(%arg0: !fir.box<!fir.array<?xi32>> {fir.bindc_name = "arraya", fir.target}) {
+ %c1 = arith.constant 1 : index
+ %c1_i64 = arith.constant 1 : i64
+ %c0 = arith.constant 0 : index
+ %0 = fir.address_of(@_QMtest10Earrayb) : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
+ %1 = fir.address_of(@_QMtest10Earrayc) : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>
+ %2 = fir.address_of(@_QMtest10En) : !fir.ref<i32>
+ %3 = fir.alloca i32 {bindc_name = "ii", uniq_name = "_QMtest10FtestEii"}
+ %4 = fir.load %2 : !fir.ref<i32>
+ %5 = fir.convert %4 : (i32) -> index
+ %6 = fir.convert %c1 : (index) -> i32
+ %7:2 = fir.do_loop %arg1 = %c1 to %5 step %c1 iter_args(%arg2 = %6) -> (index, i32) {
+ fir.store %arg2 to %3 : !fir.ref<i32>
+ %8 = fir.load %0 : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
+ %9:3 = fir.box_dims %8, %c0 : (!fir.box<!fir.heap<!fir.array<?xi32>>>, index) -> (index, index, index)
+ %10 = fir.box_addr %8 : (!fir.box<!fir.heap<!fir.array<?xi32>>>) -> !fir.heap<!fir.array<?xi32>>
+ %11 = fir.load %3 : !fir.ref<i32>
+ %12 = fir.convert %11 : (i32) -> i64
+ %13 = fir.convert %9#0 : (index) -> i64
+ %14 = arith.subi %12, %13 : i64
+ %15 = fir.coordinate_of %10, %14 : (!fir.heap<!fir.array<?xi32>>, i64) -> !fir.ref<i32>
+ %16 = fir.load %15 : !fir.ref<i32>
+ %17 = arith.subi %12, %c1_i64 : i64
+ %18 = fir.coordinate_of %arg0, %17 {test.ptr = "arraya(ii)"} : (!fir.box<!fir.array<?xi32>>, i64) -> !fir.ref<i32>
+ %19 = fir.load %18 : !fir.ref<i32>
+ %20 = arith.addi %16, %19 : i32
+ %21 = fir.load %1 : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>
+ %22:3 = fir.box_dims %21, %c0 : (!fir.box<!fir.ptr<!fir.array<?xi32>>>, index) -> (index, index, index)
+ %23 = fir.convert %22#0 : (index) -> i64
+ %24 = arith.subi %12, %23 : i64
+ %25 = fir.coordinate_of %21, %24 {test.ptr = "arrayc(ii)"} : (!fir.box<!fir.ptr<!fir.array<?xi32>>>, i64) -> !fir.ref<i32>
+ fir.store %20 to %25 : !fir.ref<i32>
+ %26 = arith.addi %arg1, %c1 : index
+ %27 = fir.load %3 : !fir.ref<i32>
+ %28 = arith.addi %27, %6 : i32
+ fir.result %26, %28 : index, i32
+ }
+ fir.store %7#1 to %3 : !fir.ref<i32>
+ return
+}
+
+// -----
+
+// CHECK-LABEL: Testing : "_QMtest11Ptest"
+// CHECK: arraya(ii)#0 <-> arrayc(ii)#0: MayAlias
+
+// module test11
+// integer, dimension(:), allocatable :: arrayB
+// integer, dimension(1000), target :: arrayC
+// integer :: N
+// contains
+// subroutine test(arrayA)
+// integer, dimension(:), target :: arrayA
+// do ii = 1, N
+// arrayC(ii) = arrayB(ii) + arrayA(ii)
+// end do
+// end subroutine
+// endmodule
+
+fir.global @_QMtest11Earrayb : !fir.box<!fir.heap<!fir.array<?xi32>>>
+fir.global @_QMtest11Earrayc target : !fir.array<1000xi32>
+fir.global @_QMtest11En : i32
+
+func.func @_QMtest11Ptest(%arg0: !fir.box<!fir.array<?xi32>> {fir.bindc_name = "arraya", fir.target}) {
+ %c1 = arith.constant 1 : index
+ %c1_i64 = arith.constant 1 : i64
+ %c0 = arith.constant 0 : index
+ %0 = fir.address_of(@_QMtest11Earrayb) : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
+ %1 = fir.address_of(@_QMtest11Earrayc) : !fir.ref<!fir.array<1000xi32>>
+ %2 = fir.address_of(@_QMtest11En) : !fir.ref<i32>
+ %3 = fir.alloca i32 {bindc_name = "ii", uniq_name = "_QMtest11FtestEii"}
+ %4 = fir.load %2 : !fir.ref<i32>
+ %5 = fir.convert %4 : (i32) -> index
+ %6 = fir.convert %c1 : (index) -> i32
+ %7:2 = fir.do_loop %arg1 = %c1 to %5 step %c1 iter_args(%arg2 = %6) -> (index, i32) {
+ fir.store %arg2 to %3 : !fir.ref<i32>
+ %8 = fir.load %0 : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
+ %9:3 = fir.box_dims %8, %c0 : (!fir.box<!fir.heap<!fir.array<?xi32>>>, index) -> (index, index, index)
+ %10 = fir.box_addr %8 : (!fir.box<!fir.heap<!fir.array<?xi32>>>) -> !fir.heap<!fir.array<?xi32>>
+ %11 = fir.load %3 : !fir.ref<i32>
+ %12 = fir.convert %11 : (i32) -> i64
+ %13 = fir.convert %9#0 : (index) -> i64
+ %14 = arith.subi %12, %13 : i64
+ %15 = fir.coordinate_of %10, %14 : (!fir.heap<!fir.array<?xi32>>, i64) -> !fir.ref<i32>
+ %16 = fir.load %15 : !fir.ref<i32>
+ %17 = arith.subi %12, %c1_i64 : i64
+ %18 = fir.coordinate_of %arg0, %17 {test.ptr = "arraya(ii)"} : (!fir.box<!fir.array<?xi32>>, i64) -> !fir.ref<i32>
+ %19 = fir.load %18 : !fir.ref<i32>
+ %20 = arith.addi %16, %19 : i32
+ %21 = fir.coordinate_of %1, %17 {test.ptr = "arrayc(ii)"} : (!fir.ref<!fir.array<1000xi32>>, i64) -> !fir.ref<i32>
+ fir.store %20 to %21 : !fir.ref<i32>
+ %22 = arith.addi %arg1, %c1 : index
+ %23 = fir.load %3 : !fir.ref<i32>
+ %24 = arith.addi %23, %6 : i32
+ fir.result %22, %24 : index, i32
+ }
+ fir.store %7#1 to %3 : !fir.ref<i32>
+ return
+}
+
+
+// -----
+
+// CHECK-LABEL: Testing : "_QMtest12Ptest"
+// CHECK: arraya(ii)#0 <-> arrayc(ii)#0: NoAlias
+
+// module test12
+// integer, dimension(:), allocatable :: arrayB
+// integer, dimension(1000) :: arrayC
+// integer :: N
+// contains
+// subroutine test(arrayA)
+// integer, dimension(:), target :: arrayA
+// do ii = 1, N
+// arrayC(ii) = arrayB(ii) + arrayA(ii)
+// end do
+// end subroutine
+// endmodule
+
+fir.global @_QMtest12Earrayb : !fir.box<!fir.heap<!fir.array<?xi32>>>
+fir.global @_QMtest12Earrayc : !fir.array<1000xi32>
+fir.global @_QMtest12En : i32
+
+func.func @_QMtest12Ptest(%arg0: !fir.box<!fir.array<?xi32>> {fir.bindc_name = "arraya", fir.target}) {
+ %c1 = arith.constant 1 : index
+ %c1_i64 = arith.constant 1 : i64
+ %c0 = arith.constant 0 : index
+ %0 = fir.address_of(@_QMtest12Earrayb) : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
+ %1 = fir.address_of(@_QMtest12Earrayc) : !fir.ref<!fir.array<1000xi32>>
+ %2 = fir.address_of(@_QMtest12En) : !fir.ref<i32>
+ %3 = fir.alloca i32 {bindc_name = "ii", uniq_name = "_QMtest12FtestEii"}
+ %4 = fir.load %2 : !fir.ref<i32>
+ %5 = fir.convert %4 : (i32) -> index
+ %6 = fir.convert %c1 : (index) -> i32
+ %7:2 = fir.do_loop %arg1 = %c1 to %5 step %c1 iter_args(%arg2 = %6) -> (index, i32) {
+ fir.store %arg2 to %3 : !fir.ref<i32>
+ %8 = fir.load %0 : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
+ %9:3 = fir.box_dims %8, %c0 : (!fir.box<!fir.heap<!fir.array<?xi32>>>, index) -> (index, index, index)
+ %10 = fir.box_addr %8 : (!fir.box<!fir.heap<!fir.array<?xi32>>>) -> !fir.heap<!fir.array<?xi32>>
+ %11 = fir.load %3 : !fir.ref<i32>
+ %12 = fir.convert %11 : (i32) -> i64
+ %13 = fir.convert %9#0 : (index) -> i64
+ %14 = arith.subi %12, %13 : i64
+ %15 = fir.coordinate_of %10, %14 : (!fir.heap<!fir.array<?xi32>>, i64) -> !fir.ref<i32>
+ %16 = fir.load %15 : !fir.ref<i32>
+ %17 = arith.subi %12, %c1_i64 : i64
+ %18 = fir.coordinate_of %arg0, %17 {test.ptr = "arraya(ii)"} : (!fir.box<!fir.array<?xi32>>, i64) -> !fir.ref<i32>
+ %19 = fir.load %18 : !fir.ref<i32>
+ %20 = arith.addi %16, %19 : i32
+ %21 = fir.coordinate_of %1, %17 {test.ptr = "arrayc(ii)"} : (!fir.ref<!fir.array<1000xi32>>, i64) -> !fir.ref<i32>
+ fir.store %20 to %21 : !fir.ref<i32>
+ %22 = arith.addi %arg1, %c1 : index
+ %23 = fir.load %3 : !fir.ref<i32>
+ %24 = arith.addi %23, %6 : i32
+ fir.result %22, %24 : index, i32
+ }
+ fir.store %7#1 to %3 : !fir.ref<i32>
+ return
+}
+
diff --git a/flang/test/Analysis/AliasAnalysis/alias-analysis-6.fir b/flang/test/Analysis/AliasAnalysis/alias-analysis-6.fir
new file mode 100644
index 000000000000000..82d89989c9cf726
--- /dev/null
+++ b/flang/test/Analysis/AliasAnalysis/alias-analysis-6.fir
@@ -0,0 +1,24 @@
+// RUN: fir-opt %s -pass-pipeline='builtin.module(func.func(test-fir-alias-analysis))'
+
+// CHECK: test_y(1)#0 <-> test_x(1)#0: MayAlias
+func.func @_QPtest(%arg0: !fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>> {fir.bindc_name = "y"}) {
+ %c1 = arith.constant 1 : index
+ %0 = fir.address_of(@_QMdataEx) : !fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>
+ %1 = fir.declare %0 {fortran_attrs = #fir.var_attrs<allocatable, target>, uniq_name = "_QMdataEx"} : (!fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>) -> !fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>
+ %2 = fir.declare %arg0 {fortran_attrs = #fir.var_attrs<pointer>, uniq_name = "_QFtestEy"} : (!fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>>) -> !fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>>
+ %3 = fir.load %2 : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>>
+ %c0 = arith.constant 0 : index
+ %4:3 = fir.box_dims %3, %c0 : (!fir.box<!fir.ptr<!fir.array<?xf32>>>, index) -> (index, index, index)
+ %5 = fir.shift %4#0 : (index) -> !fir.shift<1>
+ %6 = fir.array_coor %3(%5) %c1 {test.ptr = "test_y(1)"} : (!fir.box<!fir.ptr<!fir.array<?xf32>>>, !fir.shift<1>, index) -> !fir.ref<f32>
+ %7 = fir.load %6 : !fir.ref<f32>
+ %8 = fir.load %1 : !fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>
+ %9 = fir.box_addr %8 : (!fir.box<!fir.heap<!fir.array<?xf32>>>) -> !fir.heap<!fir.array<?xf32>>
+ %10:3 = fir.box_dims %8, %c0 : (!fir.box<!fir.heap<!fir.array<?xf32>>>, index) -> (index, index, index)
+ %11 = fir.shape_shift %10#0, %10#1 : (index, index) -> !fir.shapeshift<1>
+ %12 = fir.array_coor %9(%11) %c1 {test.ptr = "test_x(1)"} : (!fir.heap<!fir.array<?xf32>>, !fir.shapeshift<1>, index) -> !fir.ref<f32>
+ fir.store %7 to %12 : !fir.ref<f32>
+ return
+}
+fir.global @_QMdataEx target : !fir.box<!fir.heap<!fir.array<?xf32>>>
+
>From da2d755dde7eb2e6827111f21747894a856374c2 Mon Sep 17 00:00:00 2001
From: Renaud-K <rkauffmann at nvidia.com>
Date: Tue, 19 Sep 2023 09:37:52 -0700
Subject: [PATCH 2/2] Introducing the Direct SourceKind to contrast with the
Unknown and Indirect kinds
---
.../flang/Optimizer/Analysis/AliasAnalysis.h | 6 +++-
.../lib/Optimizer/Analysis/AliasAnalysis.cpp | 31 ++++++++++---------
2 files changed, 21 insertions(+), 16 deletions(-)
diff --git a/flang/include/flang/Optimizer/Analysis/AliasAnalysis.h b/flang/include/flang/Optimizer/Analysis/AliasAnalysis.h
index e96942abc22f3ee..dfcafe88fee1b5d 100644
--- a/flang/include/flang/Optimizer/Analysis/AliasAnalysis.h
+++ b/flang/include/flang/Optimizer/Analysis/AliasAnalysis.h
@@ -36,11 +36,15 @@ struct AliasAnalysis {
/// Represents memory allocated outside of a function
/// and passed to the function via host association tuple.
HostAssoc,
+ /// Represents direct memory access whose source cannot be further
+ /// determined
+ Direct,
/// Represents memory allocated by unknown means and
/// with the memory address defined by a memory reading
/// operation (e.g. fir::LoadOp).
Indirect,
- /// Represents memory allocated by unknown means.
+ /// Starting point to the analysis whereby nothing is known about
+ /// the source
Unknown);
/// Attributes of the memory source object.
diff --git a/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp b/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp
index 6f8b8b441c5dfe5..aeb6e692784f769 100644
--- a/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp
+++ b/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp
@@ -95,25 +95,26 @@ AliasResult AliasAnalysis::alias(Value lhs, Value rhs) {
llvm::dbgs() << " rhsSrc: " << rhsSrc << "\n";
llvm::dbgs() << "\n";);
- // SourceKind::Unknown is set for the addresses wrapped in a global boxes.
+ // Indirect case currently not handled. Conservatively assume
+ // it aliases with everything
+ if (lhsSrc.kind > SourceKind::Direct || rhsSrc.kind > SourceKind::Direct) {
+ return AliasResult::MayAlias;
+ }
+
+ // SourceKind::Direct is set for the addresses wrapped in a global boxes.
// ie: fir.global @_QMpointersEp : !fir.box<!fir.ptr<f32>>
// Though nothing is known about them, they would only alias with targets or
// pointers
- bool unknownSourceToNonTargetOrPointer = false;
+ bool directSourceToNonTargetOrPointer = false;
if (lhsSrc.u != rhsSrc.u) {
- if ((lhsSrc.kind == SourceKind::Unknown && !rhsSrc.isTargetOrPointer()) ||
- (rhsSrc.kind == SourceKind::Unknown && !lhsSrc.isTargetOrPointer())) {
- unknownSourceToNonTargetOrPointer = true;
- }
+ if ((lhsSrc.kind == SourceKind::Direct && !rhsSrc.isTargetOrPointer()) ||
+ (rhsSrc.kind == SourceKind::Direct && !lhsSrc.isTargetOrPointer()))
+ directSourceToNonTargetOrPointer = true;
}
- // Indirect case currently not handled. Conservatively assume
- // it aliases with everything
- if (lhsSrc.kind == SourceKind::Indirect ||
- lhsSrc.kind == SourceKind::Unknown ||
- rhsSrc.kind == SourceKind::Indirect ||
- rhsSrc.kind == SourceKind::Unknown) {
- if (!unknownSourceToNonTargetOrPointer)
+ if (lhsSrc.kind == SourceKind::Direct ||
+ rhsSrc.kind == SourceKind::Direct) {
+ if (!directSourceToNonTargetOrPointer)
return AliasResult::MayAlias;
}
@@ -308,14 +309,14 @@ AliasAnalysis::Source AliasAnalysis::getSource(mlir::Value v) {
//
// and when following through the wrapped address, capture
// the fact that there is nothing known about it. Therefore setting
- // the source to unknown.
+ // the source to Direct.
//
// When not following the wrapped address, then consider the address
// of the box, which has nothing to do with the wrapped address and
// lies in the global memory space.
if (followBoxAddr &&
mlir::isa<fir::BaseBoxType>(fir::unwrapRefType(ty)))
- type = SourceKind::Unknown;
+ type = SourceKind::Direct;
else
type = SourceKind::Global;
More information about the flang-commits
mailing list