-
Notifications
You must be signed in to change notification settings - Fork 14.1k
[DA] do not handle GEPs with different types #144088
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
base: main
Are you sure you want to change the base?
Conversation
@llvm/pr-subscribers-llvm-analysis Author: Sebastian Pop (sebpop) ChangesThis patch fixes an error in which the delinearized function for two GEPs end up to be the same except that the GEP type is different:
the result was that the dependence test was inferring a simple dependence with all elements overlapping, however because the type of elements indexed by the GEP are different, the overlap is non linear. This patch filters out such cases. Full diff: https://github.com/llvm/llvm-project/pull/144088.diff 2 Files Affected:
diff --git a/llvm/lib/Analysis/DependenceAnalysis.cpp b/llvm/lib/Analysis/DependenceAnalysis.cpp
index c1b1d002c9979..4c9ad4731b802 100644
--- a/llvm/lib/Analysis/DependenceAnalysis.cpp
+++ b/llvm/lib/Analysis/DependenceAnalysis.cpp
@@ -3642,6 +3642,16 @@ DependenceInfo::depends(Instruction *Src, Instruction *Dst,
Value *SrcPtr = getLoadStorePointerOperand(Src);
Value *DstPtr = getLoadStorePointerOperand(Dst);
+
+ if (GetElementPtrInst *SrcGEP = dyn_cast<GetElementPtrInst>(SrcPtr)) {
+ if (GetElementPtrInst *DstGEP = dyn_cast<GetElementPtrInst>(DstPtr)) {
+ if (SrcGEP->getSourceElementType() != DstGEP->getSourceElementType()) {
+ LLVM_DEBUG(dbgs() << "can't analyze GEPs with different types\n");
+ return std::make_unique<Dependence>(Src, Dst,
+ SCEVUnionPredicate(Assume, *SE));
+ }
+ }
+ }
const SCEV *SrcSCEV = SE->getSCEV(SrcPtr);
const SCEV *DstSCEV = SE->getSCEV(DstPtr);
LLVM_DEBUG(dbgs() << " SrcSCEV = " << *SrcSCEV << "\n");
diff --git a/llvm/test/Analysis/DependenceAnalysis/DifferentOffsets.ll b/llvm/test/Analysis/DependenceAnalysis/DifferentOffsets.ll
index 1f8fac3087bff..5397fa5b97caf 100644
--- a/llvm/test/Analysis/DependenceAnalysis/DifferentOffsets.ll
+++ b/llvm/test/Analysis/DependenceAnalysis/DifferentOffsets.ll
@@ -76,13 +76,9 @@ define i32 @gep_i8_vs_i32(ptr nocapture %A, i64 %n, i64 %m) {
; CHECK-NEXT: Src: store i32 42, ptr %arrayidx0, align 1 --> Dst: store i32 42, ptr %arrayidx0, align 1
; CHECK-NEXT: da analyze - none!
; CHECK-NEXT: Src: store i32 42, ptr %arrayidx0, align 1 --> Dst: store i32 42, ptr %arrayidx1, align 4
-; CHECK-NEXT: da analyze - output [|<]!
-; CHECK-NEXT: Runtime Assumptions:
-; CHECK-NEXT: Equal predicate: (zext i2 (trunc i64 %n to i2) to i64) == 0
+; CHECK-NEXT: da analyze - confused!
; CHECK-NEXT: Src: store i32 42, ptr %arrayidx1, align 4 --> Dst: store i32 42, ptr %arrayidx1, align 4
; CHECK-NEXT: da analyze - none!
-; CHECK-NEXT: Runtime Assumptions:
-; CHECK-NEXT: Equal predicate: (zext i2 (trunc i64 %n to i2) to i64) == 0
;
entry:
%arrayidx0 = getelementptr inbounds i8, ptr %A, i64 %n
@@ -98,7 +94,7 @@ define void @linearized_accesses(i64 %n, i64 %m, i64 %o, ptr %A) {
; CHECK-NEXT: Src: store i32 1, ptr %idx0, align 4 --> Dst: store i32 1, ptr %idx0, align 4
; CHECK-NEXT: da analyze - output [* * *]!
; CHECK-NEXT: Src: store i32 1, ptr %idx0, align 4 --> Dst: store i32 1, ptr %idx1, align 4
-; CHECK-NEXT: da analyze - output [* * *|<]!
+; CHECK-NEXT: da analyze - confused!
; CHECK-NEXT: Src: store i32 1, ptr %idx1, align 4 --> Dst: store i32 1, ptr %idx1, align 4
; CHECK-NEXT: da analyze - none!
;
@@ -149,8 +145,7 @@ define void @multidim_accesses(ptr %A) {
; CHECK-NEXT: Src: store i32 1, ptr %idx0, align 4 --> Dst: store i32 1, ptr %idx0, align 4
; CHECK-NEXT: da analyze - none!
; CHECK-NEXT: Src: store i32 1, ptr %idx0, align 4 --> Dst: store i32 1, ptr %idx1, align 4
-; FIXME: the dependence distance is not constant. Distance vector should be [* * *|<]!
-; CHECK-NEXT: da analyze - consistent output [0 0 0|<]!
+; CHECK-NEXT: da analyze - confused!
; CHECK-NEXT: Src: store i32 1, ptr %idx1, align 4 --> Dst: store i32 1, ptr %idx1, align 4
; CHECK-NEXT: da analyze - none!
;
|
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.
IIUIC, the problem here is the delinearization process that relies on the GEP source element type rather than the gap between two GEPs. That is, we should stop using llvm::tryDelinearizeFixedSizeImpl
. As I tried, simply removing the call of it led to regressions in some tests. Some of these failures seem to occur due to the failure of delinearization that should theoretically be possible. I believe the correct approach is to improve the DependenceInfo::tryDelinearizeParametricSize
or llvm::delinearization
at first, then proceed to delete DependenceInfo::tryDelinearizeFixedSize
.
; FIXME: the dependence distance is not constant. Distance vector should be [* * *|<]! | ||
; CHECK-NEXT: da analyze - consistent output [0 0 0|<]! | ||
; CHECK-NEXT: da analyze - confused! |
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 is just an example of DA missing some dependencies that should exist, due to the delinearization reasoning based on the GEP source element type. There are variants of this example that is not resolved by your patch, e.g., like the following:
define void @multidim_accesses(ptr %A) {
entry:
br label %for.i
for.i:
%i = phi i64 [ 0, %entry ], [ %i.inc, %for.i.inc ]
br label %for.j
for.j:
%j = phi i64 [ 0, %for.i ], [ %j.inc, %for.j.inc ]
br label %for.k
for.k:
%k = phi i64 [ 0, %for.j ], [ %k.inc, %for.k.inc ]
%k.inc = add nsw i64 %k, 1
%idx0 = getelementptr inbounds [256 x [256 x [256 x i32]]], ptr %A, i64 %i, i64 %j, i64 %k
store i64 1, ptr %idx0
%idx1 = getelementptr inbounds [256 x [256 x [256 x i32]]], ptr %A, i64 %i, i64 %j, i64 %k.inc
store i64 1, ptr %idx1
br label %for.k.inc
for.k.inc:
%k.exitcond = icmp eq i64 %k.inc, 255
br i1 %k.exitcond, label %for.j.inc, label %for.k
for.j.inc:
%j.inc = add nsw i64 %j, 1
%j.exitcond = icmp eq i64 %j.inc, 256
br i1 %j.exitcond, label %for.i.inc, label %for.j
for.i.inc:
%i.inc = add nsw i64 %i, 1
%i.exitcond = icmp eq i64 %i.inc, 256
br i1 %i.exitcond, label %end, label %for.i
end:
ret void
}
A portion of the output is as follows:
Src: store i64 1, ptr %idx0, align 4 --> Dst: store i64 1, ptr %idx1, align 4
da analyze - output [= = >]!
However, the latter half of the first store overlaps with the first half of the second store (within the same iteration). Therefore, an =
dependency exists for the k-loop, but DA currently does not recognize it.
This patch fixes an error in which the delinearized function for two GEPs end up to be the same except that the GEP type is different:
the result was that the dependence test was inferring a simple dependence with all elements overlapping, however because the type of elements indexed by the GEP are different, the overlap is non linear. This patch filters out such cases.