@@ -36,9 +36,6 @@ struct AliasAnalysis {
36
36
// / Represents memory allocated outside of a function
37
37
// / and passed to the function via host association tuple.
38
38
HostAssoc,
39
- // / Represents direct memory access whose source cannot be further
40
- // / determined
41
- Direct,
42
39
// / Represents memory allocated by unknown means and
43
40
// / with the memory address defined by a memory reading
44
41
// / operation (e.g. fir::LoadOp).
@@ -50,12 +47,85 @@ struct AliasAnalysis {
50
47
// / Attributes of the memory source object.
51
48
ENUM_CLASS (Attribute, Target, Pointer, IntentIn);
52
49
50
+ // See
51
+ // https://discourse.llvm.org/t/rfc-distinguish-between-data-and-non-data-in-fir-alias-analysis/78759/1
52
+ //
53
+ // It is possible, while following the source of a memory reference through
54
+ // the use-def chain, to arrive at the same origin, even though the starting
55
+ // points were known to not alias.
56
+ //
57
+ // clang-format off
58
+ // Example:
59
+ // ------------------- test.f90 --------------------
60
+ // module top
61
+ // real, pointer :: a(:)
62
+ // end module
63
+ //
64
+ // subroutine test()
65
+ // use top
66
+ // a(1) = 1
67
+ // end subroutine
68
+ // -------------------------------------------------
69
+ //
70
+ // flang-new -fc1 -emit-fir test.f90 -o test.fir
71
+ //
72
+ // ------------------- test.fir --------------------
73
+ // fir.global @_QMtopEa : !fir.box<!fir.ptr<!fir.array<?xf32>>>
74
+ //
75
+ // func.func @_QPtest() {
76
+ // %c1 = arith.constant 1 : index
77
+ // %cst = arith.constant 1.000000e+00 : f32
78
+ // %0 = fir.address_of(@_QMtopEa) : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>>
79
+ // %1 = fir.declare %0 {fortran_attrs = #fir.var_attrs<pointer>, uniq_name = "_QMtopEa"} : (!fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>>) -> !fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>>
80
+ // %2 = fir.load %1 : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>>
81
+ // ...
82
+ // %5 = fir.array_coor %2 %c1 : (!fir.box<!fir.ptr<!fir.array<?xf32>>>, !fir.shift<1>, index) -> !fir.ref<f32>
83
+ // fir.store %cst to %5 : !fir.ref<f32>
84
+ // return
85
+ // }
86
+ // -------------------------------------------------
87
+ //
88
+ // With high level operations, such as fir.array_coor, it is possible to
89
+ // reach into the data wrapped by the box (the descriptor). Therefore when
90
+ // asking about the memory source of %5, we are really asking about the
91
+ // source of the data of box %2.
92
+ //
93
+ // When asking about the source of %0 which is the address of the box, we
94
+ // reach the same source as in the first case: the global @_QMtopEa. Yet one
95
+ // source refers to the data while the other refers to the address of the box
96
+ // itself.
97
+ //
98
+ // To distinguish between the two, the isData flag has been added, whereby
99
+ // data is defined as any memory reference that is not a box reference.
100
+ // Additionally, because it is relied on in HLFIR lowering, we allow querying
101
+ // on a box SSA value, which is interpreted as querying on its data.
102
+ //
103
+ // So in the above example, !fir.ref<f32> and !fir.box<!fir.ptr<!fir.array<?xf32>>> is data,
104
+ // while !fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>> is not data.
105
+
106
+ // This also applies to function arguments. In the example below, %arg0
107
+ // is data, %arg1 is not data but a load of %arg1 is.
108
+ //
109
+ // func.func @_QFPtest2(%arg0: !fir.ref<f32>, %arg1: !fir.ref<!fir.box<!fir.ptr<f32>>> ) {
110
+ // %0 = fir.load %arg1 : !fir.ref<!fir.box<!fir.ptr<f32>>>
111
+ // ... }
112
+ //
113
+ // clang-format on
114
+
53
115
struct Source {
54
116
using SourceUnion = llvm::PointerUnion<mlir::SymbolRefAttr, mlir::Value>;
55
117
using Attributes = Fortran::common::EnumSet<Attribute, Attribute_enumSize>;
56
118
57
- // / Source definition of a value.
58
- SourceUnion u;
119
+ struct SourceOrigin {
120
+ // / Source definition of a value.
121
+ SourceUnion u;
122
+
123
+ // / Whether the source was reached following data or box reference
124
+ bool isData{false };
125
+ };
126
+
127
+ SourceOrigin origin;
128
+
59
129
// / Kind of the memory source.
60
130
SourceKind kind;
61
131
// / Value type of the source definition.
@@ -77,6 +147,12 @@ struct AliasAnalysis {
77
147
// / attribute.
78
148
bool isRecordWithPointerComponent () const ;
79
149
150
+ bool isDummyArgument () const ;
151
+ bool isData () const ;
152
+ bool isBoxData () const ;
153
+
154
+ mlir::Type getType () const ;
155
+
80
156
// / Return true, if `ty` is a reference type to a boxed
81
157
// / POINTER object or a raw fir::PointerType.
82
158
static bool isPointerReference (mlir::Type ty);
@@ -95,6 +171,15 @@ struct AliasAnalysis {
95
171
Source getSource (mlir::Value);
96
172
};
97
173
174
+ inline bool operator ==(const AliasAnalysis::Source::SourceOrigin &lhs,
175
+ const AliasAnalysis::Source::SourceOrigin &rhs) {
176
+ return lhs.u == rhs.u && lhs.isData == rhs.isData ;
177
+ }
178
+ inline bool operator !=(const AliasAnalysis::Source::SourceOrigin &lhs,
179
+ const AliasAnalysis::Source::SourceOrigin &rhs) {
180
+ return !(lhs == rhs);
181
+ }
182
+
98
183
inline llvm::raw_ostream &operator <<(llvm::raw_ostream &os,
99
184
const AliasAnalysis::Source &op) {
100
185
op.print (os);
0 commit comments