Skip to content

Commit f3f6bfd

Browse files
committed
cleanup
1 parent d65d76e commit f3f6bfd

1 file changed

Lines changed: 14 additions & 49 deletions

File tree

src/coreclr/jit/assertionprop.cpp

Lines changed: 14 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -5502,13 +5502,17 @@ GenTree* Compiler::optAssertionProp_BndsChk(ASSERT_VALARG_TP assertions,
55025502
ValueNum vnCurIdx = optConservativeNormalVN(arrBndsChkIdx);
55035503
ValueNum vnCurLen = optConservativeNormalVN(arrBndsChkLen);
55045504

5505+
// Let's see if we can remove the bounds check based on the ranges.
5506+
Range idxRng = GetRange(this, arrBndsChkIdx, block, assertions, /*fast*/ true);
5507+
55055508
auto dropBoundsCheck = [&](INDEBUG(const char* reason)) -> GenTree* {
55065509
JITDUMP("\nRemoving redundant (%s) bounds check in " FMT_BB ":\n", reason, compCurBB->bbNum);
55075510
DISPTREE(tree);
55085511

55095512
// Extract the side effects of idx and len. We deliberately ignore the potential null-check
55105513
// exception of the length (e.g. GT_ARR_LENGTH): having proven the bounds check redundant, we
55115514
// have also proven the length load is non-faulting. This mirrors the hack in optRemoveRangeCheck.
5515+
// TODO-Bug: We really should be extracting all side effects from the length and index here.
55125516
GenTree* sideEffList = nullptr;
55135517
gtExtractSideEffList(arrBndsChkLen, &sideEffList, GTF_ASG);
55145518
gtExtractSideEffList(arrBndsChkIdx, &sideEffList);
@@ -5534,63 +5538,26 @@ GenTree* Compiler::optAssertionProp_BndsChk(ASSERT_VALARG_TP assertions,
55345538
// Do we have a previous range check involving the same 'vnLen' upper bound?
55355539
if (curAssertion.GetOp2().GetVN() == optConservativeNormalVN(arrBndsChkLen))
55365540
{
5537-
// Do we have the exact same lower bound 'vnIdx'?
5538-
// a[i] followed by a[i]
55395541
if (curAssertion.GetOp1().GetVN() == vnCurIdx)
55405542
{
55415543
return dropBoundsCheck(INDEBUG("a[i] followed by a[i]"));
55425544
}
5543-
// Are we using zero as the index?
5544-
// It can always be considered as redundant with any previous value
5545-
// a[*] followed by a[0]
5546-
else if (vnCurIdx == vnStore->VNZeroForType(arrBndsChkIdx->TypeGet()))
5547-
{
5548-
return dropBoundsCheck(INDEBUG("a[*] followed by a[0]"));
5549-
}
5550-
else
5545+
else if (idxRng.IsConstantRange() && idxRng.LowerLimit().GetConstant() >= 0)
55515546
{
5552-
// index1 doesn't have to be a constant, it can be a Phi each predecessor of which is a constant.
5553-
// The smallest of those is what we can rely on. Example:
5554-
//
5555-
// arr[cond ? 10 : 5] = 0; // arr is at least 6 elements long
5556-
// arr[2] = 0; // arr must be at least 3 elements long
5557-
//
5558-
// or even:
5547+
// Get the range of the previously checked index for the same array length.
5548+
Range rngOfPrevIdx = RangeCheck::GetRangeFromAssertions(this, curAssertion.GetOp1().GetVN(), nullptr);
5549+
5550+
// We know the range of the previous index, we know the range of the current index.
55595551
//
5560-
// arr[cond ? 10 : 5] = 0; // arr is at least 6 elements long
5561-
// arr[cond ? 1 : 2] = 0; // arr must be at least 3 elements long
5552+
// a[prevIdx] = 0; // e.g. prevIdx's range is [5..10]
5553+
// a[currIdx] = 0; // e.g. currIdx's range is [0..5] -> drop bounds check for currIdx
55625554
//
5563-
auto tryGetMaxOrMinConst = [this](ValueNum vn, bool getMin, int* index) -> bool {
5564-
*index = getMin ? INT_MAX : INT_MIN;
5565-
return vnStore->VNVisitReachingVNs(vn,
5566-
[this, index, getMin](ValueNum vn) -> ValueNumStore::VNVisit {
5567-
int cns = 0;
5568-
if (vnStore->IsVNIntegralConstant(vn, &cns))
5569-
{
5570-
*index = getMin ? min(*index, cns) : max(*index, cns);
5571-
return ValueNumStore::VNVisit::Continue;
5572-
}
5573-
return ValueNumStore::VNVisit::Abort;
5574-
}) == ValueNumStore::VNVisit::Continue;
5575-
};
5576-
5577-
int index1;
5578-
int index2;
5579-
if (tryGetMaxOrMinConst(curAssertion.GetOp1().GetVN(), /*min*/ true, &index1) &&
5580-
tryGetMaxOrMinConst(vnCurIdx, /*max*/ false, &index2))
5555+
if (rngOfPrevIdx.IsConstantRange() &&
5556+
(rngOfPrevIdx.LowerLimit().GetConstant() >= idxRng.UpperLimit().GetConstant()))
55815557
{
5582-
// It can always be considered as redundant with any previous higher constant value
5583-
// a[K1] followed by a[K2], with K2 >= 0 and K1 >= K2
5584-
if (index2 >= 0 && index1 >= index2)
5585-
{
5586-
return dropBoundsCheck(INDEBUG("a[K1] followed by a[K2], with K2 >= 0 and K1 >= K2"));
5587-
}
5558+
return dropBoundsCheck(INDEBUG("current index is within the previous range"));
55885559
}
55895560
}
5590-
// Extend this to remove additional redundant bounds checks:
5591-
// i.e. a[i+1] followed by a[i] by using the VN(i+1) >= VN(i)
5592-
// a[i] followed by a[j] when j is known to be >= i
5593-
// a[i] followed by a[5] when i is known to be >= 5
55945561
}
55955562
}
55965563

@@ -5629,8 +5596,6 @@ GenTree* Compiler::optAssertionProp_BndsChk(ASSERT_VALARG_TP assertions,
56295596
return dropBoundsCheck(INDEBUG("a[X u% a.Length] is always within bounds"));
56305597
}
56315598

5632-
// Let's see if we can remove the bounds check based on the ranges.
5633-
Range idxRng = GetRange(this, arrBndsChkIdx, block, assertions, /*fast*/ true);
56345599
Range lenRng = GetRange(this, arrBndsChkLen, block, assertions, /*fast*/ true);
56355600

56365601
if (idxRng.IsConstantRange() && lenRng.IsConstantRange())

0 commit comments

Comments
 (0)