@@ -96,6 +96,39 @@ bool AliasAnalysis::Source::isBoxData() const {
9696 origin.isData ;
9797}
9898
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+
99132AliasResult AliasAnalysis::alias (mlir::Value lhs, mlir::Value rhs) {
100133 // TODO: alias() has to be aware of the function scopes.
101134 // After MLIR inlining, the current implementation may
@@ -118,13 +151,42 @@ AliasResult AliasAnalysis::alias(mlir::Value lhs, mlir::Value rhs) {
118151 }
119152
120153 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.
121158 if (lhsSrc.origin == rhsSrc.origin ) {
122159 LLVM_DEBUG (llvm::dbgs ()
123160 << " aliasing because same source kind and origin\n " );
124161 if (approximateSource)
125162 return AliasResult::MayAlias;
126163 return AliasResult::MustAlias;
127164 }
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+ }
128190
129191 // Two host associated accesses may overlap due to an equivalence.
130192 if (lhsSrc.kind == SourceKind::HostAssoc) {
@@ -134,12 +196,17 @@ AliasResult AliasAnalysis::alias(mlir::Value lhs, mlir::Value rhs) {
134196 }
135197
136198 Source *src1, *src2;
199+ mlir::Value *val1, *val2;
137200 if (lhsSrc.kind < rhsSrc.kind ) {
138201 src1 = &lhsSrc;
139202 src2 = &rhsSrc;
203+ val1 = &lhs;
204+ val2 = &rhs;
140205 } else {
141206 src1 = &rhsSrc;
142207 src2 = &lhsSrc;
208+ val1 = &rhs;
209+ val2 = &lhs;
143210 }
144211
145212 if (src1->kind == SourceKind::Argument &&
@@ -162,23 +229,88 @@ AliasResult AliasAnalysis::alias(mlir::Value lhs, mlir::Value rhs) {
162229 src2->attributes .set (Attribute::Target);
163230 }
164231
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.
166234 if (src1->isTargetOrPointer () && src2->isTargetOrPointer () &&
167- src1->isData () == src2->isData ()) {
235+ src1->isData () && src2->isData ()) {
168236 LLVM_DEBUG (llvm::dbgs () << " aliasing because of target or pointer\n " );
169237 return AliasResult::MayAlias;
170238 }
171239
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 " );
182314 return AliasResult::MayAlias;
183315 }
184316
@@ -278,6 +410,8 @@ AliasAnalysis::Source AliasAnalysis::getSource(mlir::Value v,
278410 followBoxData = true ;
279411 })
280412 .Case <fir::ArrayCoorOp, fir::CoordinateOp>([&](auto op) {
413+ if (isPointerReference (ty))
414+ attributes.set (Attribute::Pointer);
281415 v = op->getOperand (0 );
282416 defOp = v.getDefiningOp ();
283417 if (mlir::isa<fir::BaseBoxType>(v.getType ()))
@@ -396,6 +530,8 @@ AliasAnalysis::Source AliasAnalysis::getSource(mlir::Value v,
396530 defOp = v.getDefiningOp ();
397531 })
398532 .Case <hlfir::DesignateOp>([&](auto op) {
533+ auto varIf = llvm::cast<fir::FortranVariableOpInterface>(defOp);
534+ attributes |= getAttrsFromVariable (varIf);
399535 // Track further through the memory indexed into
400536 // => if the source arrays/structures don't alias then nor do the
401537 // results of hlfir.designate
0 commit comments