Skip to content

Commit c3f060b

Browse files
committed
[flang] approximate alias analysis support for hlfir.designate
Add a rough alias analysis rule for hlfir.designate which just follows the memref argument. This could be extended in the future to take into account the indices or derived type fields accessed to spot for provably non-overlapping cases. In the meantime, we need a flag to ensure we never say "MustAlias" when following a value through a hlfir.designate because the designate analysis is only approximate. Differential Revision: https://reviews.llvm.org/D157718
1 parent 3eff3c0 commit c3f060b

File tree

3 files changed

+97
-3
lines changed

3 files changed

+97
-3
lines changed

flang/include/flang/Optimizer/Analysis/AliasAnalysis.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,9 @@ class AliasAnalysis {
5555
mlir::Type valueType;
5656
/// Attributes of the memory source object, e.g. Target.
5757
Attributes attributes;
58+
/// Have we lost precision following the source such that
59+
/// even an exact match cannot be MustAlias?
60+
bool approximateSource;
5861

5962
/// Print information about the memory source to `os`.
6063
void print(llvm::raw_ostream &os) const;

flang/lib/Optimizer/Analysis/AliasAnalysis.cpp

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ bool AliasAnalysis::Source::isRecordWithPointerComponent() const {
7171
AliasResult AliasAnalysis::alias(Value lhs, Value rhs) {
7272
auto lhsSrc = getSource(lhs);
7373
auto rhsSrc = getSource(rhs);
74+
bool approximateSource = lhsSrc.approximateSource || rhsSrc.approximateSource;
7475
LLVM_DEBUG(llvm::dbgs() << "AliasAnalysis::alias\n";
7576
llvm::dbgs() << " lhs: " << lhs << "\n";
7677
llvm::dbgs() << " lhsSrc: " << lhsSrc << "\n";
@@ -86,8 +87,11 @@ AliasResult AliasAnalysis::alias(Value lhs, Value rhs) {
8687
return AliasResult::MayAlias;
8788

8889
if (lhsSrc.kind == rhsSrc.kind) {
89-
if (lhsSrc.u == rhsSrc.u)
90+
if (lhsSrc.u == rhsSrc.u) {
91+
if (approximateSource)
92+
return AliasResult::MayAlias;
9093
return AliasResult::MustAlias;
94+
}
9195

9296
// Allocate and global memory address cannot physically alias
9397
if (lhsSrc.kind == SourceKind::Allocate ||
@@ -195,6 +199,7 @@ AliasAnalysis::Source AliasAnalysis::getSource(mlir::Value v) {
195199
SourceKind type{SourceKind::Unknown};
196200
mlir::Type ty;
197201
bool breakFromLoop{false};
202+
bool approximateSource{false};
198203
mlir::SymbolRefAttr global;
199204
Source::Attributes attributes;
200205
while (defOp && !breakFromLoop) {
@@ -234,6 +239,19 @@ AliasAnalysis::Source AliasAnalysis::getSource(mlir::Value v) {
234239
v = op.getMemref();
235240
defOp = v.getDefiningOp();
236241
})
242+
.Case<hlfir::DesignateOp>([&](auto op) {
243+
// Track further through the memory indexed into
244+
// => if the source arrays/structures don't alias then nor do the
245+
// results of hlfir.designate
246+
v = op.getMemref();
247+
defOp = v.getDefiningOp();
248+
// TODO: there will be some cases which provably don't alias if one
249+
// takes into account the component or indices, which are currently
250+
// ignored here - leading to false positives
251+
// because of this limitation, we need to make sure we never return
252+
// MustAlias after going through a designate operation
253+
approximateSource = true;
254+
})
237255
.Default([&](auto op) {
238256
defOp = nullptr;
239257
breakFromLoop = true;
@@ -252,9 +270,9 @@ AliasAnalysis::Source AliasAnalysis::getSource(mlir::Value v) {
252270
}
253271

254272
if (type == SourceKind::Global)
255-
return {global, type, ty, attributes};
273+
return {global, type, ty, attributes, approximateSource};
256274

257-
return {v, type, ty, attributes};
275+
return {v, type, ty, attributes, approximateSource};
258276
}
259277

260278
} // namespace fir
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
// check that hlfir.designate can be followed by alias analysis
2+
3+
// use --mlir-disable-threading so that the AA queries are serialised
4+
// as well as its diagnostic output.
5+
// RUN: fir-opt %s --test-fir-alias-analysis -split-input-file --mlir-disable-threading 2>&1 | FileCheck %s
6+
7+
// designate for a derived type component:
8+
// module m
9+
// type t
10+
// real :: array(42)
11+
// end type t
12+
// type (t) :: glbl
13+
// contains
14+
// subroutine test(arg)
15+
// real :: arg(42)
16+
// glbl%array = arg
17+
// end subroutine test
18+
// end module m
19+
20+
// A global can't alias with a dummy argument
21+
// CHECK: arg#0 <-> glbl%array#0: NoAlias
22+
23+
module attributes {fir.defaultkind = "a1c4d8i4l4r4", fir.kindmap = "", llvm.target_triple = "aarch64-unknown-linux-gnu"} {
24+
fir.global @_QMmEglbl : !fir.type<_QMmTt{array:!fir.array<42xf32>}> {
25+
%0 = fir.undefined !fir.type<_QMmTt{array:!fir.array<42xf32>}>
26+
fir.has_value %0 : !fir.type<_QMmTt{array:!fir.array<42xf32>}>
27+
}
28+
func.func @_QMmPtest(%arg0: !fir.ref<!fir.array<42xf32>> {fir.bindc_name = "arg"}) {
29+
%c42 = arith.constant 42 : index
30+
%0 = fir.address_of(@_QMmEglbl) : !fir.ref<!fir.type<_QMmTt{array:!fir.array<42xf32>}>>
31+
%1:2 = hlfir.declare %0 {uniq_name = "_QMmEglbl"} : (!fir.ref<!fir.type<_QMmTt{array:!fir.array<42xf32>}>>) -> (!fir.ref<!fir.type<_QMmTt{array:!fir.array<42xf32>}>>, !fir.ref<!fir.type<_QMmTt{array:!fir.array<42xf32>}>>)
32+
%2 = fir.shape %c42 : (index) -> !fir.shape<1>
33+
%3:2 = hlfir.declare %arg0(%2) {uniq_name = "_QMmFtestEarg", test.ptr = "arg"} : (!fir.ref<!fir.array<42xf32>>, !fir.shape<1>) -> (!fir.ref<!fir.array<42xf32>>, !fir.ref<!fir.array<42xf32>>)
34+
%4 = hlfir.designate %1#0{"array"} shape %2 {test.ptr = "glbl%array"} : (!fir.ref<!fir.type<_QMmTt{array:!fir.array<42xf32>}>>, !fir.shape<1>) -> !fir.ref<!fir.array<42xf32>>
35+
hlfir.assign %3#0 to %4 : !fir.ref<!fir.array<42xf32>>, !fir.ref<!fir.array<42xf32>>
36+
return
37+
}
38+
}
39+
40+
// -----
41+
42+
// designate for an array element
43+
44+
// two dummy arguments don't alias
45+
// CHECK: array0#0 <-> array1#0: NoAlias
46+
47+
func.func @array_element(%arg0: !fir.ref<!fir.array<2x42xi32>>, %arg1: !fir.ref<!fir.array<2x42xi32>>) {
48+
%c0 = arith.constant 0 : index
49+
%c1 = arith.constant 1 : index
50+
%c41 = arith.constant 41 : index
51+
%c42 = arith.constant 42 : index
52+
%shape = fir.shape %c42 : (index) -> !fir.shape<1>
53+
%array0 = hlfir.designate %arg0 (%c0, %c0:%c41:%c1) shape %shape {test.ptr = "array0"} : (!fir.ref<!fir.array<2x42xi32>>, index, index, index, index, !fir.shape<1>) -> !fir.box<!fir.array<?xi32>>
54+
%array1 = hlfir.designate %arg1 (%c1, %c0:%c41:%c1) shape %shape {test.ptr = "array1"} : (!fir.ref<!fir.array<2x42xi32>>, index, index, index, index, !fir.shape<1>) -> !fir.box<!fir.array<?xi32>>
55+
return
56+
}
57+
58+
// -----
59+
60+
// FIXME: designate doesn't understand non-overlappning array indices
61+
// make sure that we say MayAlias and not MustAlias until array indexes are understood
62+
// CHECK: array2#0 <-> array3#0: MayAlias
63+
64+
func.func @array_element_same_source(%arg0: !fir.ref<!fir.array<2x42xi32>>) {
65+
%c0 = arith.constant 0 : index
66+
%c1 = arith.constant 1 : index
67+
%c41 = arith.constant 41 : index
68+
%c42 = arith.constant 42 : index
69+
%shape = fir.shape %c42 : (index) -> !fir.shape<1>
70+
%array2 = hlfir.designate %arg0 (%c0, %c0:%c41:%c1) shape %shape {test.ptr = "array2"} : (!fir.ref<!fir.array<2x42xi32>>, index, index, index, index, !fir.shape<1>) -> !fir.box<!fir.array<?xi32>>
71+
%array3 = hlfir.designate %arg0 (%c1, %c0:%c41:%c1) shape %shape {test.ptr = "array3"} : (!fir.ref<!fir.array<2x42xi32>>, index, index, index, index, !fir.shape<1>) -> !fir.box<!fir.array<?xi32>>
72+
return
73+
}

0 commit comments

Comments
 (0)