-
Notifications
You must be signed in to change notification settings - Fork 14.9k
[DA] Widening SCEV expressions in strong SIV test to prevent overflow #164704
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: Alireza Torabian (1997alireza) ChangesBy doubling the size of the expressions in the strong SIV test, no overflow occurs in the multiplication This patch resolves the issue #159846, and fixes the strong SIV test created in the issue #164246 by proving the dependency. While this patch resolves the overflow bug in the strong SIV test, it also prevents the test from performing and disproving the dependency in some cases. The reason behind this is due to adding Full diff: https://github.com/llvm/llvm-project/pull/164704.diff 1 Files Affected:
diff --git a/llvm/lib/Analysis/DependenceAnalysis.cpp b/llvm/lib/Analysis/DependenceAnalysis.cpp
index 853bd66c8a7f8..af900e2a92998 100644
--- a/llvm/lib/Analysis/DependenceAnalysis.cpp
+++ b/llvm/lib/Analysis/DependenceAnalysis.cpp
@@ -1668,17 +1668,35 @@ bool DependenceInfo::strongSIVtest(const SCEV *Coeff, const SCEV *SrcConst,
LLVM_DEBUG(dbgs() << "\t Delta = " << *Delta);
LLVM_DEBUG(dbgs() << ", " << *Delta->getType() << "\n");
+ TypeSize CoeffSize =
+ Coeff->getType()->getScalarType()->getPrimitiveSizeInBits();
+ TypeSize SrcSize =
+ SrcConst->getType()->getScalarType()->getPrimitiveSizeInBits();
+ TypeSize DstSize =
+ DstConst->getType()->getScalarType()->getPrimitiveSizeInBits();
+ TypeSize WideSize = std::max(CoeffSize, std::max(SrcSize, DstSize)) * 2;
+ LLVMContext &Context = CurDstLoop->getHeader()->getParent()->getContext();
+ Type *WideTy = IntegerType::get(Context, WideSize);
+ const SCEV *WideSrcC = SE->getSignExtendExpr(SrcConst, WideTy);
+ const SCEV *WideDstC = SE->getSignExtendExpr(DstConst, WideTy);
+ const SCEV *WideDelta = SE->getMinusSCEV(WideSrcC, WideDstC);
+ const SCEV *WideCoeff = SE->getSignExtendExpr(Coeff, WideTy);
+
// check that |Delta| < iteration count
- if (const SCEV *UpperBound =
- collectUpperBound(CurSrcLoop, Delta->getType())) {
- LLVM_DEBUG(dbgs() << "\t UpperBound = " << *UpperBound);
- LLVM_DEBUG(dbgs() << ", " << *UpperBound->getType() << "\n");
- const SCEV *AbsDelta =
- SE->isKnownNonNegative(Delta) ? Delta : SE->getNegativeSCEV(Delta);
- const SCEV *AbsCoeff =
- SE->isKnownNonNegative(Coeff) ? Coeff : SE->getNegativeSCEV(Coeff);
- const SCEV *Product = SE->getMulExpr(UpperBound, AbsCoeff);
- if (isKnownPredicate(CmpInst::ICMP_SGT, AbsDelta, Product)) {
+ if (const SCEV *WideUpperBound =
+ collectUpperBound(CurSrcLoop, WideDelta->getType())) {
+ LLVM_DEBUG(dbgs() << "\t WideUpperBound = " << *WideUpperBound);
+ LLVM_DEBUG(dbgs() << ", " << *WideUpperBound->getType() << "\n");
+
+ // FIXME: Use SCEV getAbsExpr function to compute the abstract values
+ const SCEV *WideAbsDelta = SE->isKnownNonNegative(WideDelta)
+ ? WideDelta
+ : SE->getNegativeSCEV(WideDelta);
+ const SCEV *WideAbsCoeff = SE->isKnownNonNegative(WideCoeff)
+ ? WideCoeff
+ : SE->getNegativeSCEV(WideCoeff);
+ const SCEV *WideProduct = SE->getMulExpr(WideUpperBound, WideAbsCoeff);
+ if (isKnownPredicate(CmpInst::ICMP_SGT, WideAbsDelta, WideProduct)) {
// Distance greater than trip count - no dependence
++StrongSIVindependence;
++StrongSIVsuccesses;
|
@kasuga-fj This patch addresses the issue with the strong SIV test you referenced in #164246. While strong SIV produces the correct result While we should resolve the bug in RDIV, I believe it may not be necessary for DA to perform the additional tests when strong SIV has already proved the dependency. Specifically, I’m referring to line 2717. Even if |
By doubling the size of the expressions in the strong SIV test, no overflow occurs in the multiplication required to check the test.
1f54190
to
271f32a
Compare
The change itself doesn't seem to be problematic, but as I mentioned in #159846 (comment), I'm now skeptical of the approach that uses wider integer types. For the cases I provided, where overflows are triggered by large constant values, I don't think they are practical enough to justify the added complexity of using wider integer types. While it's certainly beneficial to provide more accurate results in such cases, I believe it's sufficient to simply return an unknown dependency. |
What is the concern here, is it compile time or something else? large constant values are very rare in practice, so I don't think that should prevent us from merging this PR. While in principle I agree that the primary concern is correctness, and it is ok to give up on accuracy for correctness, if there is an approach that can give us more accurate results while preserving correctness, it should be preferrable. (EDIT: I haven't checked the code, but I expect for the cases where arithmetic operations on the constants do not result in overflow, widening the type should not have any impact on the complexity of the operations. Zero bits on the left side shouldn't matter). |
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.
could you please also add any required changes in the test files?
I meant the complexity of the code, not computational complexity. Since DA already has a lot of issues, I'd prefer to keep the code as simple as possible. In this specific case I think the simplest solution is to detect (perhaps potentially) overflows during the calculations and bail out if one is detected. If simply widening the integer type improves accuracy in many cases compared to bailing out when an overflow occurs, that would be great. However, looking at the tasks listed in #159846 (comment), I don't think that's the case. As you said we may be able to prove in some way that In conclusion, at the moment, I don't think widening the integer type justifies the complexity increase in the code. |
LLVM_DEBUG(dbgs() << "\t WideUpperBound = " << *WideUpperBound); | ||
LLVM_DEBUG(dbgs() << ", " << *WideUpperBound->getType() << "\n"); | ||
|
||
// FIXME: Use SCEV getAbsExpr function to compute the abstract values |
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.
JFYI: Abs
means absolute value.
That example is a separate issue. That is not related to this patch. and that case is not something that we want care about its accuracy.
The issue is not how many hanadwritten testcases can be improved. The issue is how often this can help in the real and unseen code. In an arithmetic operation where one of the involved expressions is symbolic, it is very difficult to prove the result won't overflow. Simply because often times we don't have any bound on the value of the symbolic expression. This is why I proposed widening in the first place. For symbolic intermediate computations in DA, without widening we have to give up on many real-world cases very quickly. @1997alireza can post an example to clarify this. The complexity increase is very small here. Once we miss a performance opportunity it is not easy to detect it. Once detected, it takes a lot of effort to find the root cause, come up with the idea and implement it. So if you consider longer term, I expect significant benefit from this patch. |
I'm okay if you have some real world examples (but I'm not entirely sure why wider type is useful even though we don't know the bounds of symbolic values). |
Consider this code:
if but if we extend both values to 128 bit and multiply them, the result will definitely not overflow 128 bits. So in the next step
Assuming |
But isn't that isKnownPredicate always going to fail in the case where the multiply may overflow? That means that the value is potentially larger than the original type, and AbsDelta fits within that type. Maybe I'm misunderstanding something here. By the way, it should be possible to write a test for this using |
if we exnted the type then the multiply will provably not overflow. |
By doubling the size of the expressions in the strong SIV test, no overflow occurs in the multiplication
SE->getMulExpr(WideUpperBound, WideAbsCoeff)
anymore.This patch resolves the issue #159846, and fixes the strong SIV test created in the issue #164246 by proving the dependency.
While this patch resolves the overflow bug in the strong SIV test, it also prevents the test from performing and disproving the dependency in some cases. The reason behind this is due to adding
sext
operation when we are extending the expressions, which prevents SCEV to compare the expressions and disprove the dependency in those special cases. We are working on that. Check out the progress report.