void RangeCheck::OptimizeRangeCheck(BasicBlock* block, GenTreePtr stmt, GenTreePtr treeParent) { // Check if we are dealing with a bounds check node. if (treeParent->OperGet() != GT_COMMA) { return; } // If we are not looking at array bounds check, bail. GenTreePtr tree = treeParent->gtOp.gtOp1; if (tree->gtOper != GT_ARR_BOUNDS_CHECK) { return; } GenTreeBoundsChk* bndsChk = tree->AsBoundsChk(); m_pCurBndsChk = bndsChk; GenTreePtr treeIndex = bndsChk->gtIndex; // Take care of constant index first, like a[2], for example. ValueNum idxVn = treeIndex->gtVNPair.GetConservative(); ValueNum arrLenVn = bndsChk->gtArrLen->gtVNPair.GetConservative(); int arrSize = GetArrLength(arrLenVn); JITDUMP("ArrSize for lengthVN:%03X = %d\n", arrLenVn, arrSize); if (m_pCompiler->vnStore->IsVNConstant(idxVn) && arrSize > 0) { ssize_t idxVal = -1; unsigned iconFlags = 0; if (!m_pCompiler->optIsTreeKnownIntValue(true, treeIndex, &idxVal, &iconFlags)) { return; } JITDUMP("[RangeCheck::OptimizeRangeCheck] Is index %d in <0, arrLenVn VN%X sz:%d>.\n", idxVal, arrLenVn, arrSize); if (arrSize > 0 && idxVal < arrSize && idxVal >= 0) { JITDUMP("Removing range check\n"); m_pCompiler->optRemoveRangeCheck(treeParent, stmt, true, GTF_ASG, true /* force remove */); return; } } GetRangeMap()->RemoveAll(); GetOverflowMap()->RemoveAll(); // Get the range for this index. SearchPath* path = new (m_pCompiler->getAllocator()) SearchPath(m_pCompiler->getAllocator()); Range range = GetRange(block, stmt, treeIndex, path, false DEBUGARG(0)); // If upper or lower limit is found to be unknown (top), or it was found to // be unknown because of over budget or a deep search, then return early. if (range.UpperLimit().IsUnknown() || range.LowerLimit().IsUnknown()) { // Note: If we had stack depth too deep in the GetRange call, we'd be // too deep even in the DoesOverflow call. So return early. return; } if (DoesOverflow(block, stmt, treeIndex, path)) { JITDUMP("Method determined to overflow.\n"); return; } JITDUMP("Range value %s\n", range.ToString(m_pCompiler->getAllocatorDebugOnly())); path->RemoveAll(); Widen(block, stmt, treeIndex, path, &range); // If upper or lower limit is unknown, then return. if (range.UpperLimit().IsUnknown() || range.LowerLimit().IsUnknown()) { return; } // Is the range between the lower and upper bound values. if (BetweenBounds(range, 0, bndsChk->gtArrLen)) { JITDUMP("[RangeCheck::OptimizeRangeCheck] Between bounds\n"); m_pCompiler->optRemoveRangeCheck(treeParent, stmt, true, GTF_ASG, true /* force remove */); } return; }
void RangeCheck::OptimizeRangeCheck(BasicBlock* block, GenTreeStmt* stmt, GenTree* treeParent) { // Check if we are dealing with a bounds check node. if (treeParent->OperGet() != GT_COMMA) { return; } // If we are not looking at array bounds check, bail. GenTree* tree = treeParent->gtOp.gtOp1; if (!tree->OperIsBoundsCheck()) { return; } GenTreeBoundsChk* bndsChk = tree->AsBoundsChk(); m_pCurBndsChk = bndsChk; GenTree* treeIndex = bndsChk->gtIndex; // Take care of constant index first, like a[2], for example. ValueNum idxVn = m_pCompiler->vnStore->VNConservativeNormalValue(treeIndex->gtVNPair); ValueNum arrLenVn = m_pCompiler->vnStore->VNConservativeNormalValue(bndsChk->gtArrLen->gtVNPair); int arrSize = 0; if (m_pCompiler->vnStore->IsVNConstant(arrLenVn)) { ssize_t constVal = -1; unsigned iconFlags = 0; if (m_pCompiler->optIsTreeKnownIntValue(true, bndsChk->gtArrLen, &constVal, &iconFlags)) { arrSize = (int)constVal; } } else #ifdef FEATURE_SIMD if (tree->gtOper != GT_SIMD_CHK #ifdef FEATURE_HW_INTRINSICS && tree->gtOper != GT_HW_INTRINSIC_CHK #endif // FEATURE_HW_INTRINSICS ) #endif // FEATURE_SIMD { arrSize = GetArrLength(arrLenVn); } JITDUMP("ArrSize for lengthVN:%03X = %d\n", arrLenVn, arrSize); if (m_pCompiler->vnStore->IsVNConstant(idxVn) && (arrSize > 0)) { ssize_t idxVal = -1; unsigned iconFlags = 0; if (!m_pCompiler->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_pCompiler->optRemoveRangeCheck(treeParent, stmt); return; } } GetRangeMap()->RemoveAll(); GetOverflowMap()->RemoveAll(); m_pSearchPath = new (m_alloc) SearchPath(m_alloc); // Get the range for this index. Range range = GetRange(block, treeIndex, false DEBUGARG(0)); // If upper or lower limit is found to be unknown (top), or it was found to // be unknown because of over budget or a deep search, then return early. if (range.UpperLimit().IsUnknown() || range.LowerLimit().IsUnknown()) { // Note: If we had stack depth too deep in the GetRange call, we'd be // too deep even in the DoesOverflow call. So return early. return; } if (DoesOverflow(block, treeIndex)) { JITDUMP("Method determined to overflow.\n"); return; } JITDUMP("Range value %s\n", range.ToString(m_pCompiler->getAllocatorDebugOnly())); m_pSearchPath->RemoveAll(); Widen(block, treeIndex, &range); // If upper or lower limit is unknown, then return. if (range.UpperLimit().IsUnknown() || range.LowerLimit().IsUnknown()) { return; } // Is the range between the lower and upper bound values. if (BetweenBounds(range, 0, bndsChk->gtArrLen)) { JITDUMP("[RangeCheck::OptimizeRangeCheck] Between bounds\n"); m_pCompiler->optRemoveRangeCheck(treeParent, stmt); } return; }