@@ -36,9 +36,6 @@ struct AliasAnalysis {
3636 // / Represents memory allocated outside of a function
3737 // / and passed to the function via host association tuple.
3838 HostAssoc,
39- // / Represents direct memory access whose source cannot be further
40- // / determined
41- Direct,
4239 // / Represents memory allocated by unknown means and
4340 // / with the memory address defined by a memory reading
4441 // / operation (e.g. fir::LoadOp).
@@ -50,12 +47,85 @@ struct AliasAnalysis {
5047 // / Attributes of the memory source object.
5148 ENUM_CLASS (Attribute, Target, Pointer, IntentIn);
5249
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+
53115 struct Source {
54116 using SourceUnion = llvm::PointerUnion<mlir::SymbolRefAttr, mlir::Value>;
55117 using Attributes = Fortran::common::EnumSet<Attribute, Attribute_enumSize>;
56118
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+
59129 // / Kind of the memory source.
60130 SourceKind kind;
61131 // / Value type of the source definition.
@@ -77,6 +147,12 @@ struct AliasAnalysis {
77147 // / attribute.
78148 bool isRecordWithPointerComponent () const ;
79149
150+ bool isDummyArgument () const ;
151+ bool isData () const ;
152+ bool isBoxData () const ;
153+
154+ mlir::Type getType () const ;
155+
80156 // / Return true, if `ty` is a reference type to a boxed
81157 // / POINTER object or a raw fir::PointerType.
82158 static bool isPointerReference (mlir::Type ty);
@@ -95,6 +171,15 @@ struct AliasAnalysis {
95171 Source getSource (mlir::Value);
96172};
97173
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+
98183inline llvm::raw_ostream &operator <<(llvm::raw_ostream &os,
99184 const AliasAnalysis::Source &op) {
100185 op.print (os);
0 commit comments