-
Notifications
You must be signed in to change notification settings - Fork 11.1k
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
[LAA] Fix incorrect dependency classification. #70819
Conversation
@llvm/pr-subscribers-llvm-analysis Author: Alexandros Lamprineas (labrinea) ChangesAs shown in #70473, the following loop was not considered safe to vectorize. When determining the memory access dependencies in a loop which has negative iteration step, we invert the source and sink of the dependence. Perhaps we should just invert the operands to getMinusSCEV(). This way the dependency is not regarded to be true. void vectorizable_Read_Write(int *A) { Full diff: https://github.com/llvm/llvm-project/pull/70819.diff 2 Files Affected:
diff --git a/llvm/lib/Analysis/LoopAccessAnalysis.cpp b/llvm/lib/Analysis/LoopAccessAnalysis.cpp
index 3d1edd5f038a25e..7ab2959c4d88a34 100644
--- a/llvm/lib/Analysis/LoopAccessAnalysis.cpp
+++ b/llvm/lib/Analysis/LoopAccessAnalysis.cpp
@@ -1885,17 +1885,9 @@ MemoryDepChecker::isDependent(const MemAccessInfo &A, unsigned AIdx,
// If the induction step is negative we have to invert source and sink of the
// dependence.
- if (StrideAPtr < 0) {
- std::swap(APtr, BPtr);
- std::swap(ATy, BTy);
- std::swap(Src, Sink);
- std::swap(AIsWrite, BIsWrite);
- std::swap(AIdx, BIdx);
- std::swap(StrideAPtr, StrideBPtr);
- }
-
ScalarEvolution &SE = *PSE.getSE();
- const SCEV *Dist = SE.getMinusSCEV(Sink, Src);
+ const SCEV *Dist = StrideAPtr < 0 ? SE.getMinusSCEV(Src, Sink) :
+ SE.getMinusSCEV(Sink, Src);
LLVM_DEBUG(dbgs() << "LAA: Src Scev: " << *Src << "Sink Scev: " << *Sink
<< "(Induction step: " << StrideAPtr << ")\n");
diff --git a/llvm/test/Analysis/LoopAccessAnalysis/forward-negative-step.ll b/llvm/test/Analysis/LoopAccessAnalysis/forward-negative-step.ll
index 89c1737fb730513..683c44be6da87fc 100644
--- a/llvm/test/Analysis/LoopAccessAnalysis/forward-negative-step.ll
+++ b/llvm/test/Analysis/LoopAccessAnalysis/forward-negative-step.ll
@@ -2,8 +2,6 @@
target datalayout = "e-m:e-i64:64-i128:128-n32:64-S128"
-; FIXME: This should be vectorizable
-
; void vectorizable_Read_Write(int *A) {
; for (unsigned i = 1022; i >= 0; i--)
; A[i+1] = A[i] + 1;
@@ -11,10 +9,9 @@ target datalayout = "e-m:e-i64:64-i128:128-n32:64-S128"
; CHECK: function 'vectorizable_Read_Write':
; CHECK-NEXT: for.body:
-; CHECK-NEXT: Report: unsafe dependent memory operations in loop
-; CHECK-NEXT: Forward loop carried data dependence that prevents store-to-load forwarding.
+; CHECK-NEXT: Memory dependences are safe
; CHECK-NEXT: Dependences:
-; CHECK-NEXT: ForwardButPreventsForwarding:
+; CHECK-NEXT: Forward:
; CHECK-NEXT: %0 = load i32, ptr %arrayidx, align 4 ->
; CHECK-NEXT: store i32 %add, ptr %gep, align 4
|
✅ With the latest revision this PR passed the C/C++ code formatter. |
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.
LGTM, though could you please run git-clang-format over the patch before merging.
Thanks for the update, there are a few things I'd still like to check, not sure if I will have time today, but should definitely get this done by Monday! |
Ping |
Add an additional test case where we currently incorrectly identify a dependence as Foward instead of ForwardButPreventsForwarding. Also cleans up the names in the tests a bit to improve readability.
Add an additional test case where we currently incorrectly identify a dependence as Foward instead of ForwardButPreventsForwarding. Also cleans up the names in the tests a bit to improve readability.
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.
Thanks for the update.
I had a closer look at all uses of the swapped values, and the swapping is only needed for the printing. The other uses all check that they are the same, except for the IsWrite
.
But for those all uses expect them in program order, so not swapping them makes sense.
I added another test in 5d35342 that is a variant of. the current test case that shows how we currently also incorrectly indentify a dependence that prevents forwarding as forward only (the commit also auto-generates the checks and cleans up the value names a bit).
Could you rebase and check if the test now also gets handled correctly?
Add an additional test case where we currently incorrectly identify a dependence as Foward instead of ForwardButPreventsForwarding. Also cleans up the names in the tests a bit to improve readability.
Thanks Florian, the new test does get handled correctly as far as I understand. |
This patch refactors the logic to compute the dependence distance, stride, size and write info to a separate function. This limits the scope of various A* and B* variables, which in turn makes it easier to reason about their uses. In particular this makes it more explicit why dropping the various std::swaps as done in #70819 is valid.
Thanks for rebasing on top of the test changes, good to see that's fixed now as well! I pushed a commit factoring out the logic to compute the distance, stride & co to a helper function in 9645267. This limits the scope of the swapped variables and makes it easier to see why not swapping them is fine. Would be good to rebase on top of that again and update the description of the PR with a more precise explanation of why IsWrite should not be swapped: their users rely on program order. Would still be good to retain the original printing order. After 9645267, retrieving and checking |
Adding to that the the other values don’t neddd to be swapped, as the other uses just check if they are the same. |
I must have missed this comment. I think we should not be altering the order of Sink and Source when printing them, because it would be as if we claimed that the Sink is the Source and the Source is the Sink, which is not the case. All we are doing is inverting the subtraction operands because one preceeds the other in the memory layout. Having said that @fhahn are you happy with the updated description and rebase? |
They are still swapped for computing the distance (even though |
Ping. I have changed the printing order back to how it was before and I have added a test for 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.
LGTM thanks! Please take a look at the comments for llvm/test/Analysis/LoopAccessAnalysis/print-order.ll
before landing.
As shown in llvm#70473, the following loop was not considered safe to vectorize. When determining the memory access dependencies in a loop which has negative iteration step, we invert the source and sink of the dependence. Perhaps we should just invert the operands to getMinusSCEV(). This way the dependency is not regarded to be true, since the users of the `IsWrite` variables, which correspond to each of the memory accesses, rely on program order and therefore should not be swapped. void vectorizable_Read_Write(int *A) { for (unsigned i = 1022; i >= 0; i--) A[i+1] = A[i] + 1; }
As shown in #70473, the following loop was not considered safe to vectorize.
When determining the memory access dependencies in a loop which has negative
iteration step, we invert the source and sink of the dependence. Perhaps we
should just invert the operands to getMinusSCEV(). This way the dependency is
not regarded to be true, since the users of the
IsWrite
variables, whichcorrespond to each of the memory accesses, rely on program order and therefore
should not be swapped.
void vectorizable_Read_Write(int *A) {
for (unsigned i = 1022; i >= 0; i--)
A[i+1] = A[i] + 1;
}