Skip to content

Commit f72c56d

Browse files
committed
Update GetRangeFromAssertions to handle some basic TYP_LONG scenarios where it FitsIn<int32_t>
1 parent 3b0dd88 commit f72c56d

3 files changed

Lines changed: 293 additions & 126 deletions

File tree

src/coreclr/jit/assertionprop.cpp

Lines changed: 82 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,10 @@ bool IntegralRange::Contains(int64_t value) const
300300
{
301301
rangeType = TYP_USHORT;
302302
}
303+
else if ((elementCount == 32) && varTypeIsLong(rangeType))
304+
{
305+
return {SymbolicIntegerValue::Zero, UpperBoundForType(TYP_UINT)};
306+
}
303307
break;
304308
}
305309

@@ -4070,17 +4074,20 @@ void Compiler::optAssertionProp_RangeProperties(ASSERT_VALARG_TP assertions,
40704074
}
40714075

40724076
// Let's see if MergeEdgeAssertions can help us:
4073-
if (genActualType(tree) == TYP_INT)
4077+
if (varTypeIsIntegral(tree))
40744078
{
4075-
Range rng = RangeCheck::GetRangeFromAssertions(this, treeVN, assertions);
4076-
assert(rng.IsConstantRange());
4077-
if (rng.LowerLimit().GetConstant() >= 0)
4078-
{
4079-
*isKnownNonNegative = true;
4080-
}
4081-
if ((rng.LowerLimit().GetConstant() > 0) || (rng.UpperLimit().GetConstant() < 0))
4079+
Range rng = RangeCheck::GetRangeFromAssertions(this, tree->TypeGet(), treeVN, assertions);
4080+
4081+
if (rng.IsConstantRange())
40824082
{
4083-
*isKnownNonZero = true;
4083+
if (rng.LowerLimit().GetConstant() >= 0)
4084+
{
4085+
*isKnownNonNegative = true;
4086+
}
4087+
if ((rng.LowerLimit().GetConstant() > 0) || (rng.UpperLimit().GetConstant() < 0))
4088+
{
4089+
*isKnownNonZero = true;
4090+
}
40844091
}
40854092
}
40864093
}
@@ -4101,14 +4108,17 @@ GenTree* Compiler::optAssertionProp_AddMulSub(ASSERT_VALARG_TP assertions, GenTr
41014108
{
41024109
assert(tree->OperIs(GT_MUL, GT_ADD, GT_SUB));
41034110

4104-
if (!optLocalAssertionProp && tree->TypeIs(TYP_INT) && tree->gtOverflow())
4111+
if (!optLocalAssertionProp && varTypeIsIntegral(tree) && tree->gtOverflow())
41054112
{
41064113
GenTree* op1 = tree->gtGetOp1();
41074114
GenTree* op2 = tree->gtGetOp2();
41084115

4109-
Range op1Rng = RangeCheck::GetRangeFromAssertions(this, optConservativeNormalVN(op1), assertions);
4110-
Range op2Rng = RangeCheck::GetRangeFromAssertions(this, optConservativeNormalVN(op2), assertions);
4116+
Range op1Rng =
4117+
RangeCheck::GetRangeFromAssertions(this, op1->TypeGet(), optConservativeNormalVN(op1), assertions);
4118+
Range op2Rng =
4119+
RangeCheck::GetRangeFromAssertions(this, op2->TypeGet(), optConservativeNormalVN(op2), assertions);
41114120
Range result = Limit(Limit::keUnknown);
4121+
41124122
if (tree->OperIs(GT_MUL))
41134123
{
41144124
result = RangeOps::Multiply(op1Rng, op2Rng, tree->IsUnsigned());
@@ -4481,10 +4491,10 @@ GenTree* Compiler::optAssertionPropGlobal_RelOp(ASSERT_VALARG_TP assertions,
44814491
}
44824492

44834493
// See if we can fold the relop based on range information.
4484-
// We don't need the op1->TypeIs(TYP_INT) check, but it seems to improve the TP quite a bit.
4485-
if (op1->TypeIs(TYP_INT))
4494+
// We don't need the varTypeIsIntegral(op1) check, but it seems to improve the TP quite a bit.
4495+
if (varTypeIsIntegral(op1))
44864496
{
4487-
Range relopRange = RangeCheck::GetRangeFromAssertions(this, relopVN, assertions);
4497+
Range relopRange = RangeCheck::GetRangeFromAssertions(this, tree->TypeGet(), relopVN, assertions);
44884498

44894499
int relopResult;
44904500
if (!relopRange.IsSingleValueConstant(&relopResult))
@@ -4500,8 +4510,8 @@ GenTree* Compiler::optAssertionPropGlobal_RelOp(ASSERT_VALARG_TP assertions,
45004510
}
45014511
else
45024512
{
4503-
Range op1Range = RangeCheck::GetRangeFromAssertions(this, op1VN, assertions);
4504-
Range op2Range = RangeCheck::GetRangeFromAssertions(this, op2VN, assertions);
4513+
Range op1Range = RangeCheck::GetRangeFromAssertions(this, op1->TypeGet(), op1VN, assertions);
4514+
Range op2Range = RangeCheck::GetRangeFromAssertions(this, op2->TypeGet(), op2VN, assertions);
45054515
relopRange = RangeOps::EvalRelop(tree->OperGet(), tree->IsUnsigned(), op1Range, op2Range);
45064516
}
45074517
}
@@ -4928,29 +4938,33 @@ GenTree* Compiler::optAssertionProp_Cast(ASSERT_VALARG_TP assertions,
49284938
if (FitsIn<int>(castLo) && FitsIn<int>(castHi))
49294939
{
49304940
Range castToTypeRange = Range(Limit(Limit::keConstant, (int)castLo), Limit(Limit::keConstant, (int)castHi));
4931-
if (castToTypeRange.IsConstantRange() && (genActualType(cast->CastOp()) == TYP_INT))
4932-
{
4933-
ValueNum castOpVN = optConservativeNormalVN(cast->CastOp());
4934-
Range castOpRng = RangeCheck::GetRangeFromAssertions(this, castOpVN, assertions);
4935-
assert(castOpRng.IsConstantRange());
49364941

4937-
int castFromLo = castOpRng.LowerLimit().GetConstant();
4938-
int castFromHi = castOpRng.UpperLimit().GetConstant();
4939-
int castToLo = castToTypeRange.LowerLimit().GetConstant();
4940-
int castToHi = castToTypeRange.UpperLimit().GetConstant();
4942+
GenTree* castOp = cast->CastOp();
4943+
if (castToTypeRange.IsConstantRange() && varTypeIsIntegral(castOp))
4944+
{
4945+
ValueNum castOpVN = optConservativeNormalVN(castOp);
4946+
Range castOpRng = RangeCheck::GetRangeFromAssertions(this, castOp->TypeGet(), castOpVN, assertions);
49414947

4942-
if ((castFromLo >= castToLo) && (castFromHi <= castToHi))
4948+
if (castOpRng.IsConstantRange())
49434949
{
4944-
if (canDropCast)
4950+
int castFromLo = castOpRng.LowerLimit().GetConstant();
4951+
int castFromHi = castOpRng.UpperLimit().GetConstant();
4952+
int castToLo = castToTypeRange.LowerLimit().GetConstant();
4953+
int castToHi = castToTypeRange.UpperLimit().GetConstant();
4954+
4955+
if ((castFromLo >= castToLo) && (castFromHi <= castToHi))
49454956
{
4946-
JITDUMP("Removing cast %06u as redundant based on VN assertions.\n", dspTreeID(cast));
4947-
return optAssertionProp_Update(cast->CastOp(), cast, stmt);
4948-
}
4957+
if (canDropCast)
4958+
{
4959+
JITDUMP("Removing cast %06u as redundant based on VN assertions.\n", dspTreeID(cast));
4960+
return optAssertionProp_Update(cast->CastOp(), cast, stmt);
4961+
}
49494962

4950-
assert(cast->gtOverflow());
4951-
JITDUMP("Clearing overflow flag for cast %06u based on VN assertions.\n", dspTreeID(cast));
4952-
cast->ClearOverflow();
4953-
return optAssertionProp_Update(cast, cast, stmt);
4963+
assert(cast->gtOverflow());
4964+
JITDUMP("Clearing overflow flag for cast %06u based on VN assertions.\n", dspTreeID(cast));
4965+
cast->ClearOverflow();
4966+
return optAssertionProp_Update(cast, cast, stmt);
4967+
}
49544968
}
49554969
}
49564970
}
@@ -5519,9 +5533,11 @@ GenTree* Compiler::optAssertionProp_BndsChk(ASSERT_VALARG_TP assertions, GenTree
55195533
}
55205534
#endif // FEATURE_ENABLE_NO_RANGE_CHECKS
55215535

5522-
GenTreeBoundsChk* arrBndsChk = tree->AsBoundsChk();
5523-
ValueNum vnCurIdx = vnStore->VNConservativeNormalValue(arrBndsChk->GetIndex()->gtVNPair);
5524-
ValueNum vnCurLen = vnStore->VNConservativeNormalValue(arrBndsChk->GetArrayLength()->gtVNPair);
5536+
GenTreeBoundsChk* arrBndsChk = tree->AsBoundsChk();
5537+
GenTree* arrBndsChkIdx = arrBndsChk->GetIndex();
5538+
GenTree* arrBndsChkLen = arrBndsChk->GetArrayLength();
5539+
ValueNum vnCurIdx = vnStore->VNConservativeNormalValue(arrBndsChk->GetIndex()->gtVNPair);
5540+
ValueNum vnCurLen = vnStore->VNConservativeNormalValue(arrBndsChk->GetArrayLength()->gtVNPair);
55255541

55265542
auto dropBoundsCheck = [&](INDEBUG(const char* reason)) -> GenTree* {
55275543
JITDUMP("\nVN based redundant (%s) bounds check assertion prop in " FMT_BB ":\n", reason, compCurBB->bbNum);
@@ -5549,7 +5565,7 @@ GenTree* Compiler::optAssertionProp_BndsChk(ASSERT_VALARG_TP assertions, GenTree
55495565

55505566
if ((add0 == vnCurLen) && vnStore->IsVNInt32Constant(add1))
55515567
{
5552-
Range rng = RangeCheck::GetRangeFromAssertions(this, vnCurLen, assertions);
5568+
Range rng = RangeCheck::GetRangeFromAssertions(this, arrBndsChkLen->TypeGet(), vnCurLen, assertions);
55535569
// Lower known limit of ArrLen:
55545570
const int lenLowerLimit = rng.LowerLimit().GetConstant();
55555571

@@ -5582,7 +5598,7 @@ GenTree* Compiler::optAssertionProp_BndsChk(ASSERT_VALARG_TP assertions, GenTree
55825598
assert(curAssertion.GetOp2().IsVNNeverNegative());
55835599

55845600
// Do we have a previous range check involving the same 'vnLen' upper bound?
5585-
if (curAssertion.GetOp2().GetVN() == optConservativeNormalVN(arrBndsChk->GetArrayLength()))
5601+
if (curAssertion.GetOp2().GetVN() == optConservativeNormalVN(arrBndsChkLen))
55865602
{
55875603
// Do we have the exact same lower bound 'vnIdx'?
55885604
// a[i] followed by a[i]
@@ -5593,7 +5609,7 @@ GenTree* Compiler::optAssertionProp_BndsChk(ASSERT_VALARG_TP assertions, GenTree
55935609
// Are we using zero as the index?
55945610
// It can always be considered as redundant with any previous value
55955611
// a[*] followed by a[0]
5596-
else if (vnCurIdx == vnStore->VNZeroForType(arrBndsChk->GetIndex()->TypeGet()))
5612+
else if (vnCurIdx == vnStore->VNZeroForType(arrBndsChkIdx->TypeGet()))
55975613
{
55985614
return dropBoundsCheck(INDEBUG("a[*] followed by a[0]"));
55995615
}
@@ -5645,44 +5661,40 @@ GenTree* Compiler::optAssertionProp_BndsChk(ASSERT_VALARG_TP assertions, GenTree
56455661
}
56465662

56475663
// Let's see if we can remove the bounds check based on the ranges.
5648-
if ((genActualType(vnStore->TypeOfVN(vnCurIdx)) == TYP_INT) &&
5649-
(genActualType(vnStore->TypeOfVN(vnCurLen)) == TYP_INT))
5664+
Range idxRng = RangeCheck::GetRangeFromAssertions(this, arrBndsChkIdx->TypeGet(), vnCurIdx, assertions);
5665+
Range lenRng = RangeCheck::GetRangeFromAssertions(this, arrBndsChkLen->TypeGet(), vnCurLen, assertions);
5666+
5667+
if (idxRng.IsConstantRange() && lenRng.IsConstantRange())
56505668
{
5651-
Range idxRng = RangeCheck::GetRangeFromAssertions(this, vnCurIdx, assertions);
5652-
Range lenRng = RangeCheck::GetRangeFromAssertions(this, vnCurLen, assertions);
5653-
if (idxRng.IsConstantRange() && lenRng.IsConstantRange())
5654-
{
5655-
int idxLo = idxRng.LowerLimit().GetConstant();
5656-
int idxHi = idxRng.UpperLimit().GetConstant();
5657-
int lenLo = lenRng.LowerLimit().GetConstant();
5669+
int idxLo = idxRng.LowerLimit().GetConstant();
5670+
int idxHi = idxRng.UpperLimit().GetConstant();
5671+
int lenLo = lenRng.LowerLimit().GetConstant();
56585672

5659-
// GT_BOUNDS_CHECK node has an implicit contract - the length node must always be non-negative.
5660-
// So we additionally tighten the lower bound of lenLo to be ">= 1" when we also have a
5661-
// "length != 0" assertion for it.
5662-
if ((idxLo == 0) && (idxHi == 0) && (lenLo <= 0))
5673+
// GT_BOUNDS_CHECK node has an implicit contract - the length node must always be non-negative.
5674+
// So we additionally tighten the lower bound of lenLo to be ">= 1" when we also have a
5675+
// "length != 0" assertion for it.
5676+
if ((idxLo == 0) && (idxHi == 0) && (lenLo <= 0))
5677+
{
5678+
BitVecOps::Iter iter(apTraits, assertions);
5679+
unsigned bvIndex = 0;
5680+
while (iter.NextElem(&bvIndex))
56635681
{
5664-
BitVecOps::Iter iter(apTraits, assertions);
5665-
unsigned bvIndex = 0;
5666-
while (iter.NextElem(&bvIndex))
5682+
const AssertionDsc& assertion = optGetAssertion(GetAssertionIndex(bvIndex));
5683+
if (assertion.IsConstantInt32Assertion() && assertion.KindIs(OAK_NOT_EQUAL) &&
5684+
(assertion.GetOp1().GetVN() == vnCurLen) && (assertion.GetOp2().GetIntConstant() == 0))
56675685
{
5668-
const AssertionDsc& assertion = optGetAssertion(GetAssertionIndex(bvIndex));
5669-
if (assertion.IsConstantInt32Assertion() && assertion.KindIs(OAK_NOT_EQUAL) &&
5670-
(assertion.GetOp1().GetVN() == vnCurLen) && (assertion.GetOp2().GetIntConstant() == 0))
5671-
{
5672-
lenLo = 1;
5673-
break;
5674-
}
5686+
lenLo = 1;
5687+
break;
56755688
}
56765689
}
5690+
}
56775691

5678-
// index is always within [0..lenLo) --> drop bounds check
5679-
if ((idxLo >= 0) && (idxHi < lenLo))
5680-
{
5681-
return dropBoundsCheck(INDEBUG("upper bound of index is less than lower bound of length"));
5682-
}
5692+
// index is always within [0..lenLo) --> drop bounds check
5693+
if ((idxLo >= 0) && (idxHi < lenLo))
5694+
{
5695+
return dropBoundsCheck(INDEBUG("upper bound of index is less than lower bound of length"));
56835696
}
56845697
}
5685-
56865698
return nullptr;
56875699
}
56885700

0 commit comments

Comments
 (0)