-
Notifications
You must be signed in to change notification settings - Fork 15.3k
[flang] AliasAnalysis: Fix pointer component logic #94242
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 3 commits
484cb90
9f6d2a7
78fc160
4273b38
492efb3
9b4d39a
ad0438c
1e5fdd4
3e48239
bec0399
776a17d
09e91c6
4a73682
ee248f5
a61be3a
ea40a25
ba8e749
b14ff32
b31f352
553cf74
285c2ce
27f1d94
aa4bb45
0766eba
942a625
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -70,6 +70,14 @@ void AliasAnalysis::Source::print(llvm::raw_ostream &os) const { | |
| attributes.Dump(os, EnumToString); | ||
| } | ||
|
|
||
| bool AliasAnalysis::Source::isRecordWithPointerComponent(mlir::Type ty) { | ||
| auto eleTy = fir::dyn_cast_ptrEleTy(ty); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not directly related to your patch (since you only moved that code), but I found it while testing the logic below. This should actually be Otherwise, this will miss cases as the one below where the descriptor address of "p" may alias with the data of "c".
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks for pointing that out. After some of the other issues settle, I'll think about applying that, perhaps in another PR. |
||
| if (!eleTy) | ||
| return false; | ||
| // TO DO: Look for pointer components | ||
| return mlir::isa<fir::RecordType>(eleTy); | ||
| } | ||
|
|
||
| bool AliasAnalysis::Source::isPointerReference(mlir::Type ty) { | ||
| auto eleTy = fir::dyn_cast_ptrEleTy(ty); | ||
| if (!eleTy) | ||
|
|
@@ -96,14 +104,6 @@ bool AliasAnalysis::Source::isBoxData() const { | |
| origin.isData; | ||
| } | ||
|
|
||
| bool AliasAnalysis::Source::isRecordWithPointerComponent() const { | ||
| auto eleTy = fir::dyn_cast_ptrEleTy(valueType); | ||
| if (!eleTy) | ||
| return false; | ||
| // TO DO: Look for pointer components | ||
| return mlir::isa<fir::RecordType>(eleTy); | ||
| } | ||
|
|
||
| AliasResult AliasAnalysis::alias(Value lhs, Value rhs) { | ||
| auto lhsSrc = getSource(lhs); | ||
| auto rhsSrc = getSource(rhs); | ||
|
|
@@ -122,13 +122,45 @@ AliasResult AliasAnalysis::alias(Value lhs, Value rhs) { | |
| } | ||
|
|
||
| if (lhsSrc.kind == rhsSrc.kind) { | ||
| // If the kinds and origins are the same, then lhs and rhs must alias unless | ||
| // either source is approximate. Approximate sources are for parts of the | ||
| // origin, but we don't have info here on which parts and whether they | ||
| // overlap, so we normally return MayAlias in that case. | ||
| if (lhsSrc.origin == rhsSrc.origin) { | ||
| LLVM_DEBUG(llvm::dbgs() | ||
| << " aliasing because same source kind and origin\n"); | ||
| if (approximateSource) | ||
| return AliasResult::MayAlias; | ||
| return AliasResult::MustAlias; | ||
| } | ||
| // If one value is the address of a composite, and if the other value is the | ||
| // address of a pointer/allocatable component of that composite, their | ||
| // origins compare unequal because the latter has !isData(). As for the | ||
| // address of any component vs. the address of the composite, a store to one | ||
| // can affect a load from the other, so the result should be MayAlias. To | ||
| // catch this case, we conservatively return MayAlias when one value is the | ||
| // address of a composite, the other value is non-data, and they have the | ||
| // same origin value. | ||
| // | ||
| // TODO: That logic does not check that the latter is actually a component | ||
| // of the former, so it can return MayAlias when unnecessary. For example, | ||
| // they might both be addresses of components of a larger composite. | ||
| // | ||
| // FIXME: Actually, we should generalize from | ||
| // Source::isRecordWithPointerComponent to any composite because a component | ||
| // with !isData() is not always a pointer. However, | ||
| // Source::isRecordWithPointerComponent currently doesn't actually check for | ||
| // pointer components, so it's fine for now. | ||
| if (lhsSrc.origin.u == rhsSrc.origin.u && | ||
| ((Source::isRecordWithPointerComponent(lhs.getType()) && | ||
| !rhsSrc.isData()) || | ||
| (Source::isRecordWithPointerComponent(rhs.getType()) && | ||
| !lhsSrc.isData()))) { | ||
| LLVM_DEBUG(llvm::dbgs() | ||
| << " aliasing between composite and non-data component with " | ||
| << "same source kind and origin value\n"); | ||
| return AliasResult::MayAlias; | ||
| } | ||
|
|
||
| // Two host associated accesses may overlap due to an equivalence. | ||
| if (lhsSrc.kind == SourceKind::HostAssoc) { | ||
|
|
@@ -138,12 +170,17 @@ AliasResult AliasAnalysis::alias(Value lhs, Value rhs) { | |
| } | ||
|
|
||
| Source *src1, *src2; | ||
| Value *val1, *val2; | ||
jdenny-ornl marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| if (lhsSrc.kind < rhsSrc.kind) { | ||
| src1 = &lhsSrc; | ||
| src2 = &rhsSrc; | ||
| val1 = &lhs; | ||
| val2 = &rhs; | ||
| } else { | ||
| src1 = &rhsSrc; | ||
| src2 = &lhsSrc; | ||
| val1 = &rhs; | ||
| val2 = &lhs; | ||
| } | ||
|
|
||
| if (src1->kind == SourceKind::Argument && | ||
|
|
@@ -166,21 +203,56 @@ AliasResult AliasAnalysis::alias(Value lhs, Value rhs) { | |
| src2->attributes.set(Attribute::Target); | ||
| } | ||
|
|
||
| // Dummy TARGET/POINTER argument may alias with a global TARGET/POINTER. | ||
| // Two TARGET/POINTERs may alias. | ||
| if (src1->isTargetOrPointer() && src2->isTargetOrPointer() && | ||
| src1->isData() == src2->isData()) { | ||
| LLVM_DEBUG(llvm::dbgs() << " aliasing because of target or pointer\n"); | ||
| return AliasResult::MayAlias; | ||
| } | ||
|
|
||
| // Box for POINTER component inside an object of a derived type | ||
| // may alias box of a POINTER object, as well as boxes for POINTER | ||
| // components inside two objects of derived types may alias. | ||
| if ((src1->isRecordWithPointerComponent() && src2->isTargetOrPointer()) || | ||
| (src2->isRecordWithPointerComponent() && src1->isTargetOrPointer()) || | ||
| (src1->isRecordWithPointerComponent() && | ||
| src2->isRecordWithPointerComponent())) { | ||
| LLVM_DEBUG(llvm::dbgs() << " aliasing because of pointer components\n"); | ||
| // A pointer dummy arg (but not a pointer component of a dummy arg) may alias | ||
| // a pointer component and thus the associated composite. That composite | ||
| // might be a global or another dummy arg. This is an example of the global | ||
| // composite case: | ||
| // | ||
| // module m | ||
| // type t | ||
| // real, pointer :: p | ||
| // end type | ||
| // type(t) :: a | ||
| // type(t) :: b | ||
| // contains | ||
| // subroutine test(p) | ||
| // real, pointer :: p | ||
| // p = 42 | ||
| // a = b | ||
| // print *, p | ||
| // end subroutine | ||
| // end module | ||
| // program | ||
| // use m | ||
| // real, target :: x1 = 1 | ||
| // real, target :: x2 = 2 | ||
| // a%p => x1 | ||
| // b%p => x2 | ||
| // call test(a%p) | ||
| // end | ||
| // | ||
| // The dummy argument p is an alias for a%p, even for the purposes of pointer | ||
| // association during the assignment a = b. Thus, the program should print 2. | ||
| if ((Source::isRecordWithPointerComponent(val1->getType()) && | ||
| src1->kind != SourceKind::Allocate && | ||
| src2->kind == SourceKind::Argument && | ||
|
||
| src2->attributes.test(Attribute::Pointer) && !src2->isData() && | ||
| !Source::isRecordWithPointerComponent(src2->valueType)) || | ||
| (Source::isRecordWithPointerComponent(val2->getType()) && | ||
| src2->kind != SourceKind::Allocate && | ||
| src1->kind == SourceKind::Argument && | ||
| src1->attributes.test(Attribute::Pointer) && !src1->isData() && | ||
| !Source::isRecordWithPointerComponent(src1->valueType))) { | ||
| LLVM_DEBUG(llvm::dbgs() | ||
| << " aliasing between pointer arg and composite with pointer " | ||
| << "component\n"); | ||
| return AliasResult::MayAlias; | ||
| } | ||
|
|
||
|
|
@@ -350,6 +422,8 @@ AliasAnalysis::Source AliasAnalysis::getSource(mlir::Value v) { | |
| defOp = v.getDefiningOp(); | ||
| }) | ||
| .Case<hlfir::DesignateOp>([&](auto op) { | ||
| auto varIf = llvm::cast<fir::FortranVariableOpInterface>(defOp); | ||
| attributes |= getAttrsFromVariable(varIf); | ||
| // Track further through the memory indexed into | ||
| // => if the source arrays/structures don't alias then nor do the | ||
| // results of hlfir.designate | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: it may be better to make it a private static member of the
AliasAnalysisclass.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same for the
isPointerReferencemember function that follows it?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems appropriate as well. Thank you!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done. Thanks for the review.