-
Notifications
You must be signed in to change notification settings - Fork 4.9k
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
Use rangecheck in assertprop #112766
Use rangecheck in assertprop #112766
Changes from 4 commits
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 |
---|---|---|
|
@@ -11,6 +11,7 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX | |
*/ | ||
|
||
#include "jitpch.h" | ||
#include "rangecheck.h" | ||
#ifdef _MSC_VER | ||
#pragma hdrstop | ||
#endif | ||
|
@@ -4125,6 +4126,63 @@ void Compiler::optAssertionProp_RangeProperties(ASSERT_VALARG_TP assertions, | |
} | ||
} | ||
} | ||
|
||
if (*isKnownNonZero && *isKnownNonNegative) | ||
{ | ||
return; | ||
} | ||
|
||
// Let's see if MergeEdgeAssertions can help us: | ||
if (tree->TypeIs(TYP_INT)) | ||
{ | ||
// See if (X + CNS) is known to be non-negative | ||
if (tree->OperIs(GT_ADD) && tree->gtGetOp2()->IsIntCnsFitsInI32()) | ||
{ | ||
Range rng = Range(Limit(Limit::keDependent)); | ||
ValueNum vn = vnStore->VNConservativeNormalValue(tree->gtGetOp1()->gtVNPair); | ||
RangeCheck::MergeEdgeAssertions(this, vn, ValueNumStore::NoVN, assertions, &rng, false); | ||
|
||
int cns = static_cast<int>(tree->gtGetOp2()->AsIntCon()->IconValue()); | ||
rng.LowerLimit().AddConstant(cns); | ||
rng.UpperLimit().AddConstant(cns); | ||
|
||
if (rng.LowerLimit().IsConstant()) | ||
{ | ||
// E.g. "X + -8" when X's range is [8..unknown] | ||
// it's safe to say "X + -8" is non-negative | ||
if ((rng.LowerLimit().GetConstant() == 0)) | ||
{ | ||
*isKnownNonNegative = true; | ||
} | ||
Comment on lines
+4159
to
+4162
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. Does this check not need to account for overflow? 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. but how can 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. ( 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. I was worried that for a range like "[8..unknown]", that "unknown" could mean "some computation that overflowed" and hence that the lower limit was actually smaller than 8. But it's probably ok since the range here comes from assertions only. |
||
|
||
// E.g. "X + 8" when X's range is [0..CNS] | ||
// Here we have to check the upper bound as well to avoid overflow | ||
if ((rng.LowerLimit().GetConstant() > 0) && rng.UpperLimit().IsConstant() && | ||
rng.UpperLimit().GetConstant() > rng.LowerLimit().GetConstant()) | ||
{ | ||
*isKnownNonNegative = true; | ||
*isKnownNonZero = true; | ||
} | ||
} | ||
} | ||
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. IIRC, you had a version where you tried to use range check directly on the IR node. It seems like it would catch more cases, because the logic here for additions should already be conceptually the same logic that range check has to handle additions. 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. That version had terrible TP impact and needed more touches (perhaps, its cache can be shared with rangecheck?), I might investigate it again in the future 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. Actually, I'll do it after this PR - diffs look nice (if TP regressions are mitigated) |
||
else | ||
{ | ||
Range rng = Range(Limit(Limit::keDependent)); | ||
RangeCheck::MergeEdgeAssertions(this, treeVN, ValueNumStore::NoVN, assertions, &rng, false); | ||
Limit lowerBound = rng.LowerLimit(); | ||
if (lowerBound.IsConstant()) | ||
{ | ||
if (lowerBound.GetConstant() >= 0) | ||
{ | ||
*isKnownNonNegative = true; | ||
} | ||
if (lowerBound.GetConstant() > 0) | ||
{ | ||
*isKnownNonZero = true; | ||
} | ||
} | ||
} | ||
Comment on lines
+4174
to
+4190
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. Does this part catch cases? Naively I would expect assertion prop to know to check for the "straightforward" assertions that range check is checking here already. 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. Yep, good chunk of diffs are caught by this 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. I wonder if we could get rid of some of the checks above then, I would expect there to be a good amount of duplication between range check's assertion handling and that assertion handling above. 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. I agree, I'll check what is missing in the above |
||
} | ||
} | ||
|
||
//------------------------------------------------------------------------ | ||
|
@@ -4851,12 +4909,6 @@ GenTree* Compiler::optAssertionProp_Cast(ASSERT_VALARG_TP assertions, GenTreeCas | |
// Skip over a GT_COMMA node(s), if necessary to get to the lcl. | ||
GenTree* lcl = op1->gtEffectiveVal(); | ||
|
||
// If we don't have a cast of a LCL_VAR then bail. | ||
if (!lcl->OperIs(GT_LCL_VAR)) | ||
{ | ||
return nullptr; | ||
} | ||
|
||
// Try and see if we can make this cast into a cheaper zero-extending version | ||
// if the input is known to be non-negative. | ||
if (!cast->IsUnsigned() && genActualTypeIsInt(lcl) && cast->TypeIs(TYP_LONG) && (TARGET_POINTER_SIZE == 8)) | ||
|
@@ -4870,6 +4922,12 @@ GenTree* Compiler::optAssertionProp_Cast(ASSERT_VALARG_TP assertions, GenTreeCas | |
} | ||
} | ||
|
||
// If we don't have a cast of a LCL_VAR then bail. | ||
if (!lcl->OperIs(GT_LCL_VAR)) | ||
{ | ||
return nullptr; | ||
} | ||
|
||
IntegralRange range = IntegralRange::ForCastInput(cast); | ||
AssertionIndex index = optAssertionIsSubrange(lcl, range, assertions); | ||
if (index != NO_ASSERTION_INDEX) | ||
|
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.
Return value needs to be checked?
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.
Ah, didn't realize AddConstant doesn't do anything if cns limit overflows. Added!