@@ -96,6 +96,39 @@ bool AliasAnalysis::Source::isBoxData() const {
96
96
origin.isData ;
97
97
}
98
98
99
+ bool AliasAnalysis::Source::mayBeDummyArgOrHostAssoc () const {
100
+ return kind != SourceKind::Allocate && kind != SourceKind::Global;
101
+ }
102
+
103
+ bool AliasAnalysis::Source::mayBePtrDummyArgOrHostAssoc () const {
104
+ // Must alias like dummy arg (or HostAssoc).
105
+ if (!mayBeDummyArgOrHostAssoc ())
106
+ return false ;
107
+ // Must be address of the dummy arg not of a dummy arg component.
108
+ if (isRecordWithPointerComponent (valueType))
109
+ return false ;
110
+ // Must be address *of* (not *in*) a pointer.
111
+ return attributes.test (Attribute::Pointer) && !isData ();
112
+ }
113
+
114
+ bool AliasAnalysis::Source::mayBeActualArg () const {
115
+ return kind != SourceKind::Allocate;
116
+ }
117
+
118
+ bool AliasAnalysis::Source::mayBeActualArgWithPtr (
119
+ const mlir::Value *val) const {
120
+ // Must not be local.
121
+ if (!mayBeActualArg ())
122
+ return false ;
123
+ // Can be address *of* (not *in*) a pointer.
124
+ if (attributes.test (Attribute::Pointer) && !isData ())
125
+ return true ;
126
+ // Can be address of a composite with a pointer component.
127
+ if (isRecordWithPointerComponent (val->getType ()))
128
+ return true ;
129
+ return false ;
130
+ }
131
+
99
132
AliasResult AliasAnalysis::alias (mlir::Value lhs, mlir::Value rhs) {
100
133
// TODO: alias() has to be aware of the function scopes.
101
134
// After MLIR inlining, the current implementation may
@@ -118,13 +151,42 @@ AliasResult AliasAnalysis::alias(mlir::Value lhs, mlir::Value rhs) {
118
151
}
119
152
120
153
if (lhsSrc.kind == rhsSrc.kind ) {
154
+ // If the kinds and origins are the same, then lhs and rhs must alias unless
155
+ // either source is approximate. Approximate sources are for parts of the
156
+ // origin, but we don't have info here on which parts and whether they
157
+ // overlap, so we normally return MayAlias in that case.
121
158
if (lhsSrc.origin == rhsSrc.origin ) {
122
159
LLVM_DEBUG (llvm::dbgs ()
123
160
<< " aliasing because same source kind and origin\n " );
124
161
if (approximateSource)
125
162
return AliasResult::MayAlias;
126
163
return AliasResult::MustAlias;
127
164
}
165
+ // If one value is the address of a composite, and if the other value is the
166
+ // address of a pointer/allocatable component of that composite, their
167
+ // origins compare unequal because the latter has !isData(). As for the
168
+ // address of any component vs. the address of the composite, a store to one
169
+ // can affect a load from the other, so the result should be MayAlias. To
170
+ // catch this case, we conservatively return MayAlias when one value is the
171
+ // address of a composite, the other value is non-data, and they have the
172
+ // same origin value.
173
+ //
174
+ // TODO: That logic does not check that the latter is actually a component
175
+ // of the former, so it can return MayAlias when unnecessary. For example,
176
+ // they might both be addresses of components of a larger composite.
177
+ //
178
+ // FIXME: Actually, we should generalize from isRecordWithPointerComponent
179
+ // to any composite because a component with !isData() is not always a
180
+ // pointer. However, Source::isRecordWithPointerComponent currently doesn't
181
+ // actually check for pointer components, so it's fine for now.
182
+ if (lhsSrc.origin .u == rhsSrc.origin .u &&
183
+ ((isRecordWithPointerComponent (lhs.getType ()) && !rhsSrc.isData ()) ||
184
+ (isRecordWithPointerComponent (rhs.getType ()) && !lhsSrc.isData ()))) {
185
+ LLVM_DEBUG (llvm::dbgs ()
186
+ << " aliasing between composite and non-data component with "
187
+ << " same source kind and origin value\n " );
188
+ return AliasResult::MayAlias;
189
+ }
128
190
129
191
// Two host associated accesses may overlap due to an equivalence.
130
192
if (lhsSrc.kind == SourceKind::HostAssoc) {
@@ -134,12 +196,17 @@ AliasResult AliasAnalysis::alias(mlir::Value lhs, mlir::Value rhs) {
134
196
}
135
197
136
198
Source *src1, *src2;
199
+ mlir::Value *val1, *val2;
137
200
if (lhsSrc.kind < rhsSrc.kind ) {
138
201
src1 = &lhsSrc;
139
202
src2 = &rhsSrc;
203
+ val1 = &lhs;
204
+ val2 = &rhs;
140
205
} else {
141
206
src1 = &rhsSrc;
142
207
src2 = &lhsSrc;
208
+ val1 = &rhs;
209
+ val2 = &lhs;
143
210
}
144
211
145
212
if (src1->kind == SourceKind::Argument &&
@@ -162,23 +229,88 @@ AliasResult AliasAnalysis::alias(mlir::Value lhs, mlir::Value rhs) {
162
229
src2->attributes .set (Attribute::Target);
163
230
}
164
231
165
- // Dummy TARGET/POINTER argument may alias with a global TARGET/POINTER.
232
+ // Two TARGET/POINTERs may alias. The logic here focuses on data. Handling
233
+ // of non-data is included below.
166
234
if (src1->isTargetOrPointer () && src2->isTargetOrPointer () &&
167
- src1->isData () == src2->isData ()) {
235
+ src1->isData () && src2->isData ()) {
168
236
LLVM_DEBUG (llvm::dbgs () << " aliasing because of target or pointer\n " );
169
237
return AliasResult::MayAlias;
170
238
}
171
239
172
- // Box for POINTER component inside an object of a derived type
173
- // may alias box of a POINTER object, as well as boxes for POINTER
174
- // components inside two objects of derived types may alias.
175
- if ((isRecordWithPointerComponent (src1->valueType ) &&
176
- src2->isTargetOrPointer ()) ||
177
- (isRecordWithPointerComponent (src2->valueType ) &&
178
- src1->isTargetOrPointer ()) ||
179
- (isRecordWithPointerComponent (src1->valueType ) &&
180
- isRecordWithPointerComponent (src2->valueType ))) {
181
- LLVM_DEBUG (llvm::dbgs () << " aliasing because of pointer components\n " );
240
+ // Aliasing for dummy arg with target attribute.
241
+ //
242
+ // The address of a dummy arg (or HostAssoc) may alias the address of a
243
+ // non-local (global or another dummy arg) when both have target attributes.
244
+ // If either is a composite, addresses of components may alias as well.
245
+ //
246
+ // The previous "if" calling isTargetOrPointer casts a very wide net and so
247
+ // reports MayAlias for many such cases that would otherwise be reported here.
248
+ // It specifically skips such cases where one or both values have !isData()
249
+ // (e.g., address *of* pointer/allocatable component vs. address of
250
+ // composite), so this "if" catches those cases.
251
+ if (src1->attributes .test (Attribute::Target) &&
252
+ src2->attributes .test (Attribute::Target) &&
253
+ ((src1->mayBeDummyArgOrHostAssoc () && src2->mayBeActualArg ()) ||
254
+ (src2->mayBeDummyArgOrHostAssoc () && src1->mayBeActualArg ()))) {
255
+ LLVM_DEBUG (llvm::dbgs ()
256
+ << " aliasing between targets where one is a dummy arg\n " );
257
+ return AliasResult::MayAlias;
258
+ }
259
+
260
+ // Aliasing for dummy arg that is a pointer.
261
+ //
262
+ // The address of a pointer dummy arg (but not a pointer component of a dummy
263
+ // arg) may alias the address of either (1) a non-local pointer or (2) thus a
264
+ // non-local composite with a pointer component. A non-local might be a
265
+ // global or another dummy arg. The following is an example of the global
266
+ // composite case:
267
+ //
268
+ // module m
269
+ // type t
270
+ // real, pointer :: p
271
+ // end type
272
+ // type(t) :: a
273
+ // type(t) :: b
274
+ // contains
275
+ // subroutine test(p)
276
+ // real, pointer :: p
277
+ // p = 42
278
+ // a = b
279
+ // print *, p
280
+ // end subroutine
281
+ // end module
282
+ // program main
283
+ // use m
284
+ // real, target :: x1 = 1
285
+ // real, target :: x2 = 2
286
+ // a%p => x1
287
+ // b%p => x2
288
+ // call test(a%p)
289
+ // end
290
+ //
291
+ // The dummy argument p is an alias for a%p, even for the purposes of pointer
292
+ // association during the assignment a = b. Thus, the program should print 2.
293
+ //
294
+ // The same is true when p is HostAssoc. For example, we might replace the
295
+ // test subroutine above with:
296
+ //
297
+ // subroutine test(p)
298
+ // real, pointer :: p
299
+ // call internal()
300
+ // contains
301
+ // subroutine internal()
302
+ // p = 42
303
+ // a = b
304
+ // print *, p
305
+ // end subroutine
306
+ // end subroutine
307
+ if ((src1->mayBePtrDummyArgOrHostAssoc () &&
308
+ src2->mayBeActualArgWithPtr (val2)) ||
309
+ (src2->mayBePtrDummyArgOrHostAssoc () &&
310
+ src1->mayBeActualArgWithPtr (val1))) {
311
+ LLVM_DEBUG (llvm::dbgs ()
312
+ << " aliasing between pointer dummy arg and either pointer or "
313
+ << " composite with pointer component\n " );
182
314
return AliasResult::MayAlias;
183
315
}
184
316
@@ -278,6 +410,8 @@ AliasAnalysis::Source AliasAnalysis::getSource(mlir::Value v,
278
410
followBoxData = true ;
279
411
})
280
412
.Case <fir::ArrayCoorOp, fir::CoordinateOp>([&](auto op) {
413
+ if (isPointerReference (ty))
414
+ attributes.set (Attribute::Pointer);
281
415
v = op->getOperand (0 );
282
416
defOp = v.getDefiningOp ();
283
417
if (mlir::isa<fir::BaseBoxType>(v.getType ()))
@@ -396,6 +530,8 @@ AliasAnalysis::Source AliasAnalysis::getSource(mlir::Value v,
396
530
defOp = v.getDefiningOp ();
397
531
})
398
532
.Case <hlfir::DesignateOp>([&](auto op) {
533
+ auto varIf = llvm::cast<fir::FortranVariableOpInterface>(defOp);
534
+ attributes |= getAttrsFromVariable (varIf);
399
535
// Track further through the memory indexed into
400
536
// => if the source arrays/structures don't alias then nor do the
401
537
// results of hlfir.designate
0 commit comments