From d1885463420d7be3cea166f6f0fa50984443a277 Mon Sep 17 00:00:00 2001 From: Egor Bogatov Date: Tue, 9 Jun 2026 01:23:30 +0200 Subject: [PATCH 1/3] Clean up in rangecheck Remove the now-redundant optIsTreeKnownIntValue helper and the ad-hoc constant-index/arrSize handling in OptimizeRangeCheck. The array size is now derived consistently through GetRangeFromAssertions, which also recovers the exact size for new T[cns].Length via TryGetNewArrSize. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/coreclr/jit/assertionprop.cpp | 49 ----------------- src/coreclr/jit/compiler.h | 1 - src/coreclr/jit/rangecheck.cpp | 91 +++++++++---------------------- 3 files changed, 26 insertions(+), 115 deletions(-) diff --git a/src/coreclr/jit/assertionprop.cpp b/src/coreclr/jit/assertionprop.cpp index cd0f28d0bc2914..6a059f865f4116 100644 --- a/src/coreclr/jit/assertionprop.cpp +++ b/src/coreclr/jit/assertionprop.cpp @@ -1337,55 +1337,6 @@ AssertionIndex Compiler::optCreateAssertion(GenTree* op1, GenTree* op2, bool equ return NO_ASSERTION_INDEX; } -/***************************************************************************** - * - * If tree is a constant node holding an integral value, retrieve the value in - * pConstant. If the method returns true, pConstant holds the appropriate - * constant. Set "vnBased" to true to indicate local or global assertion prop. - * "pFlags" indicates if the constant is a handle marked by GTF_ICON_HDL_MASK. - */ -bool Compiler::optIsTreeKnownIntValue(bool vnBased, GenTree* tree, ssize_t* pConstant, GenTreeFlags* pFlags) -{ - // Is Local assertion prop? - if (!vnBased) - { - if (tree->OperIs(GT_CNS_INT)) - { - *pConstant = tree->AsIntCon()->IconValue(); - *pFlags = tree->GetIconHandleFlag(); - return true; - } - return false; - } - - // Global assertion prop - ValueNum vn = vnStore->VNConservativeNormalValue(tree->gtVNPair); - if (!vnStore->IsVNConstant(vn)) - { - return false; - } - - // ValueNumber 'vn' indicates that this node evaluates to a constant - - var_types vnType = vnStore->TypeOfVN(vn); - if (vnType == TYP_INT) - { - *pConstant = vnStore->ConstantValue(vn); - *pFlags = vnStore->IsVNHandle(vn) ? vnStore->GetHandleFlags(vn) : GTF_EMPTY; - return true; - } -#ifdef TARGET_64BIT - else if (vnType == TYP_LONG) - { - *pConstant = vnStore->ConstantValue(vn); - *pFlags = vnStore->IsVNHandle(vn) ? vnStore->GetHandleFlags(vn) : GTF_EMPTY; - return true; - } -#endif - - return false; -} - /***************************************************************************** * * Given an assertion add it to the assertion table diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index ebce8cdf96ca8e..5607ef74193291 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -9075,7 +9075,6 @@ class Compiler // Assertion prop data flow functions. PhaseStatus optAssertionPropMain(); Statement* optVNAssertionPropCurStmt(BasicBlock* block, Statement* stmt); - bool optIsTreeKnownIntValue(bool vnBased, GenTree* tree, ssize_t* pConstant, GenTreeFlags* pIconFlags); ASSERT_TP* optInitAssertionDataflowFlags(); ASSERT_TP* optComputeAssertionGen(); diff --git a/src/coreclr/jit/rangecheck.cpp b/src/coreclr/jit/rangecheck.cpp index f855c9c5175970..5a9282faf027a8 100644 --- a/src/coreclr/jit/rangecheck.cpp +++ b/src/coreclr/jit/rangecheck.cpp @@ -272,73 +272,15 @@ void RangeCheck::OptimizeRangeCheck(BasicBlock* block, Statement* stmt, GenTree* return; } - GenTree* comma = treeParent->OperIs(GT_COMMA) ? treeParent : nullptr; - GenTreeBoundsChk* bndsChk = tree->AsBoundsChk(); - m_preferredBound = m_compiler->vnStore->VNConservativeNormalValue(bndsChk->GetArrayLength()->gtVNPair); - GenTree* treeIndex = bndsChk->GetIndex(); + GenTree* comma = treeParent->OperIs(GT_COMMA) ? treeParent : nullptr; + GenTreeBoundsChk* bndsChk = tree->AsBoundsChk(); + GenTree* treeIndex = bndsChk->GetIndex(); // Take care of constant index first, like a[2], for example. - ValueNum idxVn = m_compiler->vnStore->VNConservativeNormalValue(treeIndex->gtVNPair); - ValueNum arrLenVn = m_compiler->vnStore->VNConservativeNormalValue(bndsChk->GetArrayLength()->gtVNPair); - int arrSize = 0; + ValueNum idxVn = m_compiler->optConservativeNormalVN(treeIndex); + ValueNum arrLenVn = m_compiler->optConservativeNormalVN(bndsChk->GetArrayLength()); - if (m_compiler->vnStore->IsVNConstant(arrLenVn)) - { - ssize_t constVal = -1; - GenTreeFlags iconFlags = GTF_EMPTY; - - if (m_compiler->optIsTreeKnownIntValue(true, bndsChk->GetArrayLength(), &constVal, &iconFlags)) - { - arrSize = (int)constVal; - } - } - else - { - arrSize = GetArrLength(arrLenVn); - - // if we can't find the array length, see if there - // are any assertions about the array size we can use to get a minimum length - if (arrSize <= 0) - { - JITDUMP("Looking for array size assertions for: " FMT_VN "\n", arrLenVn); - Range arrLength = Range(Limit(Limit::keDependent)); - MergeEdgeAssertions(m_compiler, arrLenVn, arrLenVn, block->bbAssertionIn, &arrLength); - if (arrLength.lLimit.IsConstant()) - { - arrSize = arrLength.lLimit.GetConstant(); - } - else - { - // Fast path didn't find anything - do the slow SSA-based search. - arrLength = GetRangeWorker(block, bndsChk->GetArrayLength(), false DEBUGARG(0)); - if (arrLength.lLimit.IsConstant()) - { - arrSize = arrLength.lLimit.GetConstant(); - } - } - } - } - - JITDUMP("ArrSize for lengthVN:%03X = %d\n", arrLenVn, arrSize); - if (m_compiler->vnStore->IsVNConstant(idxVn) && (arrSize > 0)) - { - ssize_t idxVal = -1; - GenTreeFlags iconFlags = GTF_EMPTY; - if (!m_compiler->optIsTreeKnownIntValue(true, treeIndex, &idxVal, &iconFlags)) - { - return; - } - - JITDUMP("[RangeCheck::OptimizeRangeCheck] Is index %d in <0, arrLenVn " FMT_VN " sz:%d>.\n", idxVal, arrLenVn, - arrSize); - if ((idxVal < arrSize) && (idxVal >= 0)) - { - JITDUMP("Removing range check\n"); - m_compiler->optRemoveRangeCheck(bndsChk, comma, stmt); - m_updateStmt = true; - return; - } - } + m_preferredBound = arrLenVn; // Special case: arr[arr.Length - CNS] if we know that arr.Length >= CNS // We assume that SUB(x, CNS) is canonized into ADD(x, -CNS) @@ -428,6 +370,9 @@ void RangeCheck::OptimizeRangeCheck(BasicBlock* block, Statement* stmt, GenTree* return; } + Range arrSizeRng = GetRangeFromAssertions(m_compiler, arrLenVn, block->bbAssertionIn); + int arrSize = arrSizeRng.LowerLimit().GetConstant(); + // Is the range between the lower and upper bound values. if (BetweenBounds(range, bndsChk->GetArrayLength(), arrSize)) { @@ -840,9 +785,25 @@ Range RangeCheck::GetRangeFromAssertionsWorker( case VNF_MDARR_LENGTH: case VNF_ARR_LENGTH: + { result.lLimit = Limit(Limit::keConstant, 0); result.uLimit = Limit(Limit::keConstant, CORINFO_Array_MaxLength); - break; + + int size; + if (comp->vnStore->TryGetNewArrSize(comp->vnStore->GetArrForLenVn(num), &size) && (size >= 0)) + { + result.lLimit = Limit(Limit::keConstant, size); + result.uLimit = Limit(Limit::keConstant, size); + } + } + break; + + case VNF_StrFastAllocate: + { + result.lLimit = Limit(Limit::keConstant, 0); + result.uLimit = Limit(Limit::keConstant, CORINFO_String_MaxLength); + } + break; case VNF_GT: case VNF_GT_UN: From b07444f2bf3933e1557af24d318e2e220067a7b8 Mon Sep 17 00:00:00 2001 From: Egor Bogatov Date: Tue, 9 Jun 2026 01:25:50 +0200 Subject: [PATCH 2/3] remove VNF_StrFastAllocate --- src/coreclr/jit/rangecheck.cpp | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/coreclr/jit/rangecheck.cpp b/src/coreclr/jit/rangecheck.cpp index 5a9282faf027a8..32b612cedd2e52 100644 --- a/src/coreclr/jit/rangecheck.cpp +++ b/src/coreclr/jit/rangecheck.cpp @@ -798,13 +798,6 @@ Range RangeCheck::GetRangeFromAssertionsWorker( } break; - case VNF_StrFastAllocate: - { - result.lLimit = Limit(Limit::keConstant, 0); - result.uLimit = Limit(Limit::keConstant, CORINFO_String_MaxLength); - } - break; - case VNF_GT: case VNF_GT_UN: case VNF_GE: From 70245ada45a909b1245c0b4967eb717e702aec7f Mon Sep 17 00:00:00 2001 From: Egor Bogatov Date: Tue, 9 Jun 2026 01:29:51 +0200 Subject: [PATCH 3/3] revert change --- src/coreclr/jit/rangecheck.cpp | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/src/coreclr/jit/rangecheck.cpp b/src/coreclr/jit/rangecheck.cpp index 32b612cedd2e52..222c0b839950f6 100644 --- a/src/coreclr/jit/rangecheck.cpp +++ b/src/coreclr/jit/rangecheck.cpp @@ -785,18 +785,9 @@ Range RangeCheck::GetRangeFromAssertionsWorker( case VNF_MDARR_LENGTH: case VNF_ARR_LENGTH: - { result.lLimit = Limit(Limit::keConstant, 0); result.uLimit = Limit(Limit::keConstant, CORINFO_Array_MaxLength); - - int size; - if (comp->vnStore->TryGetNewArrSize(comp->vnStore->GetArrForLenVn(num), &size) && (size >= 0)) - { - result.lLimit = Limit(Limit::keConstant, size); - result.uLimit = Limit(Limit::keConstant, size); - } - } - break; + break; case VNF_GT: case VNF_GT_UN: