diff --git a/src/coreclr/jit/assertionprop.cpp b/src/coreclr/jit/assertionprop.cpp index 45ca1da3915f47..e1f24367d17eae 100644 --- a/src/coreclr/jit/assertionprop.cpp +++ b/src/coreclr/jit/assertionprop.cpp @@ -979,6 +979,11 @@ void Compiler::optAssertionInit(bool isLocalProp) optAssertionCount = 0; optAssertionPropagated = false; bbJtrueAssertionOut = nullptr; + optCanPropLclVar = false; + optCanPropEqual = false; + optCanPropNonNull = false; + optCanPropBndsChk = false; + optCanPropSubRange = false; } #ifdef DEBUG @@ -1996,6 +2001,13 @@ AssertionIndex Compiler::optAddAssertion(AssertionDsc* newAssertion) } #endif // DEBUG + // Track the shortcircuit criterias + optCanPropLclVar |= newAssertion->CanPropLclVar(); + optCanPropEqual |= newAssertion->CanPropEqualOrNotEqual(); + optCanPropNonNull |= newAssertion->CanPropNonNull(); + optCanPropSubRange |= newAssertion->CanPropSubRange(); + optCanPropBndsChk |= newAssertion->CanPropBndsCheck(); + // Assertion mask bits are [index + 1]. if (optLocalAssertionProp) { @@ -2826,7 +2838,7 @@ AssertionIndex Compiler::optFindComplementary(AssertionIndex assertIndex) // AssertionIndex Compiler::optAssertionIsSubrange(GenTree* tree, IntegralRange range, ASSERT_VALARG_TP assertions) { - if (!optLocalAssertionProp && BitVecOps::IsEmpty(apTraits, assertions)) + if ((!optLocalAssertionProp && BitVecOps::IsEmpty(apTraits, assertions)) || !optCanPropSubRange) { return NO_ASSERTION_INDEX; } @@ -2836,8 +2848,7 @@ AssertionIndex Compiler::optAssertionIsSubrange(GenTree* tree, IntegralRange ran AssertionDsc* curAssertion = optGetAssertion(index); if ((optLocalAssertionProp || BitVecOps::IsMember(apTraits, assertions, index - 1)) && // either local prop or use propagated assertions - (curAssertion->assertionKind == OAK_SUBRANGE) && - (curAssertion->op1.kind == O1K_LCLVAR)) + curAssertion->CanPropSubRange()) { // For local assertion prop use comparison on locals, and use comparison on vns for global prop. bool isEqual = optLocalAssertionProp @@ -3597,6 +3608,13 @@ GenTree* Compiler::optAssertionProp_LclVar(ASSERT_VALARG_TP assertions, GenTreeL return nullptr; } + // There are no constant assertions for structs in global propagation. + // + if ((!optLocalAssertionProp && varTypeIsStruct(tree)) || !optCanPropLclVar) + { + return nullptr; + } + BitVecOps::Iter iter(apTraits, assertions); unsigned index = 0; while (iter.NextElem(&index)) @@ -3608,7 +3626,7 @@ GenTree* Compiler::optAssertionProp_LclVar(ASSERT_VALARG_TP assertions, GenTreeL } // See if the variable is equal to a constant or another variable. AssertionDsc* curAssertion = optGetAssertion(assertionIndex); - if (curAssertion->assertionKind != OAK_EQUAL || curAssertion->op1.kind != O1K_LCLVAR) + if (!curAssertion->CanPropLclVar()) { continue; } @@ -3795,7 +3813,7 @@ AssertionIndex Compiler::optLocalAssertionIsEqualOrNotEqual( // AssertionIndex Compiler::optGlobalAssertionIsEqualOrNotEqual(ASSERT_VALARG_TP assertions, GenTree* op1, GenTree* op2) { - if (BitVecOps::IsEmpty(apTraits, assertions)) + if (BitVecOps::IsEmpty(apTraits, assertions) || !optCanPropEqual) { return NO_ASSERTION_INDEX; } @@ -3809,7 +3827,7 @@ AssertionIndex Compiler::optGlobalAssertionIsEqualOrNotEqual(ASSERT_VALARG_TP as break; } AssertionDsc* curAssertion = optGetAssertion(assertionIndex); - if ((curAssertion->assertionKind != OAK_EQUAL && curAssertion->assertionKind != OAK_NOT_EQUAL)) + if (!curAssertion->CanPropEqualOrNotEqual()) { continue; } @@ -3848,7 +3866,7 @@ AssertionIndex Compiler::optGlobalAssertionIsEqualOrNotEqual(ASSERT_VALARG_TP as */ AssertionIndex Compiler::optGlobalAssertionIsEqualOrNotEqualZero(ASSERT_VALARG_TP assertions, GenTree* op1) { - if (BitVecOps::IsEmpty(apTraits, assertions)) + if (BitVecOps::IsEmpty(apTraits, assertions) || !optCanPropEqual) { return NO_ASSERTION_INDEX; } @@ -3862,7 +3880,7 @@ AssertionIndex Compiler::optGlobalAssertionIsEqualOrNotEqualZero(ASSERT_VALARG_T break; } AssertionDsc* curAssertion = optGetAssertion(assertionIndex); - if ((curAssertion->assertionKind != OAK_EQUAL && curAssertion->assertionKind != OAK_NOT_EQUAL)) + if (!curAssertion->CanPropEqualOrNotEqual()) { continue; } @@ -4487,6 +4505,11 @@ AssertionIndex Compiler::optAssertionIsNonNullInternal(GenTree* op, *pVnBased = false; #endif + if (!optCanPropNonNull) + { + return NO_ASSERTION_INDEX; + } + // If local assertion prop use lcl comparison, else use VN comparison. if (!optLocalAssertionProp) { @@ -4531,12 +4554,7 @@ AssertionIndex Compiler::optAssertionIsNonNullInternal(GenTree* op, break; } AssertionDsc* curAssertion = optGetAssertion(assertionIndex); - if (curAssertion->assertionKind != OAK_NOT_EQUAL) - { - continue; - } - - if (curAssertion->op2.vn != ValueNumStore::VNForNull()) + if (!curAssertion->CanPropNonNull()) { continue; } @@ -4681,7 +4699,7 @@ GenTree* Compiler::optAssertionProp_Call(ASSERT_VALARG_TP assertions, GenTreeCal */ GenTree* Compiler::optAssertionProp_BndsChk(ASSERT_VALARG_TP assertions, GenTree* tree, Statement* stmt) { - if (optLocalAssertionProp) + if (optLocalAssertionProp || !optCanPropBndsChk) { return nullptr; } diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index 3291aca767c382..0b201557d526cd 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -7110,6 +7110,31 @@ class Compiler return ((assertionKind == OAK_EQUAL) || (assertionKind == OAK_NOT_EQUAL)) && (op2.kind == O2K_CONST_INT); } + bool CanPropLclVar() + { + return assertionKind == OAK_EQUAL && op1.kind == O1K_LCLVAR; + } + + bool CanPropEqualOrNotEqual() + { + return assertionKind == OAK_EQUAL || assertionKind == OAK_NOT_EQUAL; + } + + bool CanPropNonNull() + { + return assertionKind == OAK_NOT_EQUAL && op2.vn == ValueNumStore::VNForNull(); + } + + bool CanPropBndsCheck() + { + return op1.kind == O1K_ARR_BND; + } + + bool CanPropSubRange() + { + return assertionKind == OAK_SUBRANGE && op1.kind == O1K_LCLVAR; + } + static bool SameKind(AssertionDsc* a1, AssertionDsc* a2) { return a1->assertionKind == a2->assertionKind && a1->op1.kind == a2->op1.kind && @@ -7231,6 +7256,11 @@ class Compiler AssertionDsc* optAssertionTabPrivate; // table that holds info about value assignments AssertionIndex optAssertionCount; // total number of assertions in the assertion table AssertionIndex optMaxAssertionCount; + bool optCanPropLclVar; + bool optCanPropEqual; + bool optCanPropNonNull; + bool optCanPropBndsChk; + bool optCanPropSubRange; public: void optVnNonNullPropCurStmt(BasicBlock* block, Statement* stmt, GenTree* tree);