Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions src/coreclr/inc/switches.h
Original file line number Diff line number Diff line change
Expand Up @@ -119,10 +119,6 @@

#endif // _DEBUG

// MUST NEVER CHECK IN WITH THIS ENABLED.
// This is just for convenience in doing performance investigations in a checked-out enlistment.
// #define FEATURE_ENABLE_NO_RANGE_CHECKS

// This controls whether a compilation-timing feature that relies on Windows APIs, if available, else direct
// hardware instructions (rdtsc), for accessing high-resolution hardware timers is enabled. This is disabled
// in Silverlight (just to avoid thinking about whether the extra code space is worthwhile).
Expand Down
73 changes: 19 additions & 54 deletions src/coreclr/jit/assertionprop.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4958,23 +4958,6 @@ GenTree* Compiler::optAssertionProp_Cast(ASSERT_VALARG_TP assertions,
return nullptr;
}

/*****************************************************************************
*
* Given a tree with an array bounds check node, eliminate it because it was
* checked already in the program.
*/
GenTree* Compiler::optAssertionProp_Comma(ASSERT_VALARG_TP assertions, GenTree* tree, Statement* stmt)
{
// Remove the bounds check as part of the GT_COMMA node since we need parent pointer to remove nodes.
// When processing visits the bounds check, it sets the throw kind to None if the check is redundant.
if (tree->gtGetOp1()->OperIs(GT_BOUNDS_CHECK) && ((tree->gtGetOp1()->gtFlags & GTF_CHK_INDEX_INBND) != 0))
{
optRemoveCommaBasedRangeCheck(tree, stmt);
return optAssertionProp_Update(tree, tree, stmt);
}
return nullptr;
}

//------------------------------------------------------------------------
// optAssertionProp_Ind: see if we can prove the indirection can't cause
// and exception.
Expand Down Expand Up @@ -5458,59 +5441,34 @@ GenTree* Compiler::optAssertionProp_Call(ASSERT_VALARG_TP assertions, GenTreeCal
*/
GenTree* Compiler::optAssertionProp_BndsChk(ASSERT_VALARG_TP assertions, GenTree* tree, Statement* stmt)
{
if (optLocalAssertionProp)
{
return nullptr;
}

assert(tree->OperIs(GT_BOUNDS_CHECK));

#ifdef FEATURE_ENABLE_NO_RANGE_CHECKS
if (JitConfig.JitNoRngChks())
if (optLocalAssertionProp)
{
#ifdef DEBUG
if (verbose)
{
printf("\nFlagging check redundant due to JitNoRngChks in " FMT_BB ":\n", compCurBB->bbNum);
gtDispTree(tree, nullptr, nullptr, true);
}
#endif // DEBUG
tree->gtFlags |= GTF_CHK_INDEX_INBND;
// We don't have the right kind of assertions to optimize bounds checks in local assertion prop.
return nullptr;
}
#endif // FEATURE_ENABLE_NO_RANGE_CHECKS

GenTreeBoundsChk* arrBndsChk = tree->AsBoundsChk();
GenTree* arrBndsChkIdx = arrBndsChk->GetIndex();
GenTree* arrBndsChkLen = arrBndsChk->GetArrayLength();
ValueNum vnCurIdx = vnStore->VNConservativeNormalValue(arrBndsChkIdx->gtVNPair);
ValueNum vnCurLen = vnStore->VNConservativeNormalValue(arrBndsChkLen->gtVNPair);
ValueNum vnCurIdx = optConservativeNormalVN(arrBndsChkIdx);
ValueNum vnCurLen = optConservativeNormalVN(arrBndsChkLen);

auto dropBoundsCheck = [&](INDEBUG(const char* reason)) -> GenTree* {
JITDUMP("\nVN based redundant (%s) bounds check assertion prop in " FMT_BB ":\n", reason, compCurBB->bbNum);
JITDUMP("\nRemoving redundant (%s) bounds check in " FMT_BB ":\n", reason, compCurBB->bbNum);
DISPTREE(tree);
if (arrBndsChk != stmt->GetRootNode())
{
// Defer the removal.
arrBndsChk->gtFlags |= GTF_CHK_INDEX_INBND;
return nullptr;
}

GenTree* newTree = optRemoveStandaloneRangeCheck(arrBndsChk, stmt);
return optAssertionProp_Update(newTree, arrBndsChk, stmt);
// Extract the side-effects of idx and len without taking the root (GT_BOUNDS_CHECK itself) into account.
GenTree* nothing = gtWrapWithSideEffects(gtNewNothingNode(), tree, GTF_ALL_EFFECT, /*ignoreRoot*/ true);
return optAssertionProp_Update(nothing, arrBndsChk, stmt);
};

BitVecOps::Iter iter(apTraits, assertions);
unsigned index = 0;
while (iter.NextElem(&index))
{
AssertionIndex assertionIndex = GetAssertionIndex(index);
if (assertionIndex > optAssertionCount)
{
break;
}
// If it is not a nothrow assertion, skip.
const AssertionDsc& curAssertion = optGetAssertion(assertionIndex);
const AssertionDsc& curAssertion = optGetAssertion(GetAssertionIndex(index));
if (!curAssertion.IsBoundsCheckNoThrow())
Comment thread
EgorBo marked this conversation as resolved.
{
continue;
Expand Down Expand Up @@ -5652,6 +5610,7 @@ GenTree* Compiler::optAssertionProp_BndsChk(ASSERT_VALARG_TP assertions, GenTree
return dropBoundsCheck(INDEBUG("upper bound of index is less than lower bound of length"));
}
}

return nullptr;
}

Expand Down Expand Up @@ -5780,6 +5739,15 @@ GenTree* Compiler::optAssertionProp(ASSERT_VALARG_TP assertions, GenTree* tree,
case GT_UDIV:
return optAssertionProp_ModDiv(assertions, tree->AsOp(), stmt, block);

#if defined(TARGET_AMD64)
// An MD array access loads several metadata fields (the per-dimension lengths and lower bounds),
// most of which are needed for the element-address computation, not just for the bounds checks.
// Proving them non-faulting pins each load with an ordering side effect (see
// On targets with load-pair addressing (e.g. arm64) GTF_ORDER_SIDEEFFCT
// prevents these adjacent metadata loads from being combined into ldp.
case GT_MDARR_LENGTH:
case GT_MDARR_LOWER_BOUND:
#endif
case GT_ARR_LENGTH:
// Unfortunately, doing this in LocalAP produces an asymmetry in exception sets between
// uses/defs that CSE does not manage to make good use of. As a result, some bounds checks are no longer
Expand All @@ -5800,9 +5768,6 @@ GenTree* Compiler::optAssertionProp(ASSERT_VALARG_TP assertions, GenTree* tree,
case GT_BOUNDS_CHECK:
return optAssertionProp_BndsChk(assertions, tree, stmt);

case GT_COMMA:
return optAssertionProp_Comma(assertions, tree, stmt);

case GT_CAST:
return optAssertionProp_Cast(assertions, tree->AsCast(), stmt, block);

Expand Down
2 changes: 0 additions & 2 deletions src/coreclr/jit/compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -7427,7 +7427,6 @@ class Compiler
public:
PhaseStatus rangeCheckPhase();
GenTree* optRemoveRangeCheck(GenTreeBoundsChk* check, GenTree* comma, Statement* stmt);
GenTree* optRemoveStandaloneRangeCheck(GenTreeBoundsChk* check, Statement* stmt);
void optRemoveCommaBasedRangeCheck(GenTree* comma, Statement* stmt);

protected:
Expand Down Expand Up @@ -9134,7 +9133,6 @@ class Compiler
GenTree* optAssertionProp_Cast(ASSERT_VALARG_TP assertions, GenTreeCast* cast, Statement* stmt, BasicBlock* block);
GenTree* optAssertionProp_Call(ASSERT_VALARG_TP assertions, GenTreeCall* call, Statement* stmt);
GenTree* optAssertionProp_RelOp(ASSERT_VALARG_TP assertions, GenTree* tree, Statement* stmt, BasicBlock* block);
GenTree* optAssertionProp_Comma(ASSERT_VALARG_TP assertions, GenTree* tree, Statement* stmt);
GenTree* optAssertionProp_BndsChk(ASSERT_VALARG_TP assertions, GenTree* tree, Statement* stmt);
GenTree* optAssertionPropGlobal_RelOp(ASSERT_VALARG_TP assertions,
GenTree* tree,
Expand Down
2 changes: 0 additions & 2 deletions src/coreclr/jit/gentree.h
Original file line number Diff line number Diff line change
Expand Up @@ -528,8 +528,6 @@ enum GenTreeFlags : unsigned

GTF_DIV_MOD_NO_OVERFLOW = 0x40000000, // GT_DIV, GT_MOD -- Div or mod definitely does not overflow.

GTF_CHK_INDEX_INBND = 0x80000000, // GT_BOUNDS_CHECK -- have proven this check is always in-bounds

GTF_ARRLEN_NONFAULTING = 0x20000000, // GT_ARR_LENGTH -- An array length operation that cannot fault. Same as GT_IND_NONFAULTING.

GTF_MDARRLEN_NONFAULTING = 0x20000000, // GT_MDARR_LENGTH -- An MD array length operation that cannot fault. Same as GT_IND_NONFAULTING.
Expand Down
4 changes: 0 additions & 4 deletions src/coreclr/jit/jitconfigvalues.h
Original file line number Diff line number Diff line change
Expand Up @@ -574,10 +574,6 @@ RELEASE_CONFIG_INTEGER(JitInlineSIMDMultiplier, "JitInlineSIMDMultiplier", 3)
// Ex lclMAX_TRACKED constant.
RELEASE_CONFIG_INTEGER(JitMaxLocalsToTrack, "JitMaxLocalsToTrack", 0x400)

#if defined(FEATURE_ENABLE_NO_RANGE_CHECKS)
RELEASE_CONFIG_INTEGER(JitNoRngChks, "JitNoRngChks", 0) // If 1, don't generate range checks
#endif

OPT_CONFIG_INTEGER(JitDoAssertionProp, "JitDoAssertionProp", 1) // Perform assertion propagation optimization
OPT_CONFIG_INTEGER(JitDoCopyProp, "JitDoCopyProp", 1) // Perform copy propagation on variables that appear redundant
OPT_CONFIG_INTEGER(JitDoOptimizeIVs, "JitDoOptimizeIVs", 1) // Perform optimization of induction variables
Expand Down
20 changes: 0 additions & 20 deletions src/coreclr/jit/optimizer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5593,26 +5593,6 @@ GenTree* Compiler::optRemoveRangeCheck(GenTreeBoundsChk* check, GenTree* comma,
return check;
}

//------------------------------------------------------------------------------
// optRemoveStandaloneRangeCheck : A thin wrapper over optRemoveRangeCheck that removes standalone checks.
//
// Arguments:
// check - The standalone top-level CHECK node.
// stmt - The statement "check" is a root node of.
//
// Return Value:
// If "check" has no side effects, it is retuned, bashed to a no-op.
// If it has side effects, the tree that executes them is returned.
//
GenTree* Compiler::optRemoveStandaloneRangeCheck(GenTreeBoundsChk* check, Statement* stmt)
{
assert(check != nullptr);
assert(stmt != nullptr);
assert(check == stmt->GetRootNode());

return optRemoveRangeCheck(check, nullptr, stmt);
}

//------------------------------------------------------------------------------
// optRemoveCommaBasedRangeCheck : A thin wrapper over optRemoveRangeCheck that removes COMMA-based checks.
//
Expand Down
Loading