diff --git a/src/coreclr/jit/assertionprop.cpp b/src/coreclr/jit/assertionprop.cpp index ef91f916fb9563..ae8c38daadb92c 100644 --- a/src/coreclr/jit/assertionprop.cpp +++ b/src/coreclr/jit/assertionprop.cpp @@ -4962,22 +4962,11 @@ GenTree* Compiler::optAssertionProp_Ind(ASSERT_VALARG_TP assertions, GenTree* tr // Arguments: // op - tree to check // assertions - set of live assertions -// pVnBased - [out] set to true if value numbers were used -// pIndex - [out] the assertion used in the proof // // Return Value: // true if the tree's value will be non-null // -// Notes: -// Sets "pVnBased" if the assertion is value number based. If no matching -// assertions are found from the table, then returns "NO_ASSERTION_INDEX." -// -// If both VN and assertion table yield a matching assertion, "pVnBased" -// is only set and the return value is "NO_ASSERTION_INDEX." -// -bool Compiler::optAssertionIsNonNull(GenTree* op, - ASSERT_VALARG_TP assertions DEBUGARG(bool* pVnBased) - DEBUGARG(AssertionIndex* pIndex)) +bool Compiler::optAssertionIsNonNull(GenTree* op, ASSERT_VALARG_TP assertions) { if (op->OperIs(GT_ADD) && op->AsOp()->gtGetOp2()->IsCnsIntOrI() && !fgIsBigOffset(op->AsOp()->gtGetOp2()->AsIntCon()->IconValue())) @@ -4985,90 +4974,39 @@ bool Compiler::optAssertionIsNonNull(GenTree* op, op = op->AsOp()->gtGetOp1(); } - bool vnBased = (!optLocalAssertionProp && vnStore->IsKnownNonNull(op->gtVNPair.GetConservative())); -#ifdef DEBUG - *pIndex = NO_ASSERTION_INDEX; - *pVnBased = vnBased; -#endif - - if (vnBased) + // Fast path when we have a VN + if (!optLocalAssertionProp && vnStore->IsKnownNonNull(op->gtVNPair.GetConservative())) { return true; } - op = op->gtEffectiveVal(); - - if (!op->OperIs(GT_LCL_VAR)) + if (!optCanPropNonNull || BitVecOps::MayBeUninit(assertions)) { return false; } - AssertionIndex index = optAssertionIsNonNullInternal(op, assertions DEBUGARG(pVnBased)); -#ifdef DEBUG - *pIndex = index; -#endif - return index != NO_ASSERTION_INDEX; -} - -//------------------------------------------------------------------------ -// optAssertionIsNonNullInternal: see if we can prove a tree's value will -// be non-null based on assertions -// -// Arguments: -// op - tree to check -// assertions - set of live assertions -// pVnBased - [out] set to true if value numbers were used -// -// Return Value: -// index of assertion, or NO_ASSERTION_INDEX -// -AssertionIndex Compiler::optAssertionIsNonNullInternal(GenTree* op, - ASSERT_VALARG_TP assertions DEBUGARG(bool* pVnBased)) -{ - -#ifdef DEBUG - // Initialize the out param - // - *pVnBased = false; -#endif - - if (!optCanPropNonNull) + op = op->gtEffectiveVal(); + if (!op->OperIs(GT_LCL_VAR)) { - return NO_ASSERTION_INDEX; + return false; } // If local assertion prop use lcl comparison, else use VN comparison. if (!optLocalAssertionProp) { - if (BitVecOps::MayBeUninit(assertions) || BitVecOps::IsEmpty(apTraits, assertions)) - { - return NO_ASSERTION_INDEX; - } - // Look at both the top-level vn, and // the vn we get by stripping off any constant adds. // - ValueNum vn = vnStore->VNConservativeNormalValue(op->gtVNPair); - ValueNum vnBase = vn; - VNFuncApp funcAttr; - - while (vnStore->GetVNFunc(vnBase, &funcAttr) && (funcAttr.m_func == (VNFunc)GT_ADD)) + ValueNum vn = vnStore->VNConservativeNormalValue(op->gtVNPair); + if (vn == ValueNumStore::NoVN) { - if (vnStore->IsVNConstant(funcAttr.m_args[1]) && varTypeIsIntegral(vnStore->TypeOfVN(funcAttr.m_args[1]))) - { - vnBase = funcAttr.m_args[0]; - } - else if (vnStore->IsVNConstant(funcAttr.m_args[0]) && - varTypeIsIntegral(vnStore->TypeOfVN(funcAttr.m_args[0]))) - { - vnBase = funcAttr.m_args[1]; - } - else - { - break; - } + return false; } + ValueNum vnBase = vn; + target_ssize_t offset = 0; + vnStore->PeelOffsets(&vnBase, &offset); + // Check each assertion to find if we have a vn != null assertion. // BitVecOps::Iter iter(apTraits, assertions); @@ -5076,26 +5014,11 @@ AssertionIndex Compiler::optAssertionIsNonNullInternal(GenTree* while (iter.NextElem(&index)) { AssertionIndex assertionIndex = GetAssertionIndex(index); - if (assertionIndex > optAssertionCount) - { - break; - } - AssertionDsc* curAssertion = optGetAssertion(assertionIndex); - if (!curAssertion->CanPropNonNull()) - { - continue; - } - - if ((curAssertion->op1.vn != vn) && (curAssertion->op1.vn != vnBase)) + AssertionDsc* curAssertion = optGetAssertion(assertionIndex); + if (curAssertion->CanPropNonNull() && ((curAssertion->op1.vn == vn) || (curAssertion->op1.vn == vnBase))) { - continue; + return true; } - -#ifdef DEBUG - *pVnBased = true; -#endif - - return assertionIndex; } } else @@ -5119,11 +5042,11 @@ AssertionIndex Compiler::optAssertionIsNonNullInternal(GenTree* (curAssertion->op2.kind == O2K_CONST_INT) && // op2 (curAssertion->op1.lcl.lclNum == lclNum) && (curAssertion->op2.u1.iconVal == 0)) { - return assertionIndex; + return true; } } } - return NO_ASSERTION_INDEX; + return false; } //------------------------------------------------------------------------ @@ -5177,20 +5100,10 @@ GenTree* Compiler::optNonNullAssertionProp_Call(ASSERT_VALARG_TP assertions, Gen GenTree* op1 = call->gtArgs.GetThisArg()->GetNode(); noway_assert(op1 != nullptr); -#ifdef DEBUG - bool vnBased = false; - AssertionIndex index = NO_ASSERTION_INDEX; -#endif - if (optAssertionIsNonNull(op1, assertions DEBUGARG(&vnBased) DEBUGARG(&index))) + if (optAssertionIsNonNull(op1, assertions)) { -#ifdef DEBUG - if (verbose) - { - (vnBased) ? printf("\nVN based non-null prop in " FMT_BB ":\n", compCurBB->bbNum) - : printf("\nNon-null prop for index #%02u in " FMT_BB ":\n", index, compCurBB->bbNum); - gtDispTree(call, nullptr, nullptr, true); - } -#endif + JITDUMP("Non-null assertion prop for tree [%06d] in " FMT_BB ":\n", dspTreeID(op1), compCurBB->bbNum); + call->gtFlags &= ~GTF_CALL_NULLCHECK; call->gtFlags &= ~GTF_EXCEPT; noway_assert(call->gtFlags & GTF_SIDE_EFFECT); @@ -5219,20 +5132,10 @@ bool Compiler::optNonNullAssertionProp_Ind(ASSERT_VALARG_TP assertions, GenTree* return false; } -#ifdef DEBUG - bool vnBased = false; - AssertionIndex index = NO_ASSERTION_INDEX; -#endif - if (optAssertionIsNonNull(indir->AsIndir()->Addr(), assertions DEBUGARG(&vnBased) DEBUGARG(&index))) + if (optAssertionIsNonNull(indir->AsIndir()->Addr(), assertions)) { -#ifdef DEBUG - if (verbose) - { - (vnBased) ? printf("\nVN based non-null prop in " FMT_BB ":\n", compCurBB->bbNum) - : printf("\nNon-null prop for index #%02u in " FMT_BB ":\n", index, compCurBB->bbNum); - gtDispTree(indir, nullptr, nullptr, true); - } -#endif + JITDUMP("Non-null assertion prop for indirection [%06d] in " FMT_BB ":\n", dspTreeID(indir), compCurBB->bbNum); + indir->gtFlags &= ~GTF_EXCEPT; indir->gtFlags |= GTF_IND_NONFAULTING; @@ -5429,11 +5332,9 @@ GenTree* Compiler::optAssertionProp_Call(ASSERT_VALARG_TP assertions, GenTreeCal } // Leave a hint for fgLateCastExpansion that obj is never null. - INDEBUG(AssertionIndex nonNullIdx = NO_ASSERTION_INDEX); - INDEBUG(bool vnBased = false); // GTF_CALL_M_CAST_CAN_BE_EXPANDED check is to improve TP if (((call->gtCallMoreFlags & GTF_CALL_M_CAST_CAN_BE_EXPANDED) != 0) && - optAssertionIsNonNull(objArg, assertions DEBUGARG(&vnBased) DEBUGARG(&nonNullIdx))) + optAssertionIsNonNull(objArg, assertions)) { call->gtCallMoreFlags |= GTF_CALL_M_CAST_OBJ_NONNULL; return optAssertionProp_Update(call, call, stmt); diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index dd967f33cbed9e..2f5d219ed94d43 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -8247,10 +8247,8 @@ class Compiler // Used for respective assertion propagations. AssertionIndex optAssertionIsSubrange(GenTree* tree, IntegralRange range, ASSERT_VALARG_TP assertions); AssertionIndex optAssertionIsSubtype(GenTree* tree, GenTree* methodTableArg, ASSERT_VALARG_TP assertions); - AssertionIndex optAssertionIsNonNullInternal(GenTree* op, ASSERT_VALARG_TP assertions DEBUGARG(bool* pVnBased)); bool optAssertionVNIsNonNull(ValueNum vn, ASSERT_VALARG_TP assertions); - bool optAssertionIsNonNull(GenTree* op, - ASSERT_VALARG_TP assertions DEBUGARG(bool* pVnBased) DEBUGARG(AssertionIndex* pIndex)); + bool optAssertionIsNonNull(GenTree* op, ASSERT_VALARG_TP assertions); AssertionIndex optGlobalAssertionIsEqualOrNotEqual(ASSERT_VALARG_TP assertions, GenTree* op1, GenTree* op2); AssertionIndex optGlobalAssertionIsEqualOrNotEqualZero(ASSERT_VALARG_TP assertions, GenTree* op1); diff --git a/src/coreclr/jit/valuenum.cpp b/src/coreclr/jit/valuenum.cpp index ecd7f4fbdf475c..3de41dc1bccf3c 100644 --- a/src/coreclr/jit/valuenum.cpp +++ b/src/coreclr/jit/valuenum.cpp @@ -12123,28 +12123,15 @@ bool Compiler::GetObjectHandleAndOffset(GenTree* tree, ssize_t* byteOffset, CORI return false; } - ValueNum treeVN = tree->gtVNPair.GetLiberal(); - VNFuncApp funcApp; - target_ssize_t offset = 0; - while (vnStore->GetVNFunc(treeVN, &funcApp) && (funcApp.m_func == (VNFunc)GT_ADD)) + ValueNum treeVN = tree->gtVNPair.GetLiberal(); + if (treeVN == ValueNumStore::NoVN) { - if (vnStore->IsVNConstantNonHandle(funcApp.m_args[0]) && (vnStore->TypeOfVN(funcApp.m_args[0]) == TYP_I_IMPL)) - { - offset += vnStore->ConstantValue(funcApp.m_args[0]); - treeVN = funcApp.m_args[1]; - } - else if (vnStore->IsVNConstantNonHandle(funcApp.m_args[1]) && - (vnStore->TypeOfVN(funcApp.m_args[1]) == TYP_I_IMPL)) - { - offset += vnStore->ConstantValue(funcApp.m_args[1]); - treeVN = funcApp.m_args[0]; - } - else - { - return false; - } + return false; } + target_ssize_t offset = 0; + vnStore->PeelOffsets(&treeVN, &offset); + if (vnStore->IsVNObjHandle(treeVN)) { *pObj = vnStore->ConstantObjHandle(treeVN); @@ -12269,7 +12256,6 @@ bool Compiler::fgValueNumberConstLoad(GenTreeIndir* tree) size_t index = -1; // First, let see if we have PtrToArrElem - ValueNum addr = funcApp.m_args[0]; if (funcApp.m_func == VNF_PtrToArrElem) { ValueNum arrVN = funcApp.m_args[1]; @@ -12283,34 +12269,9 @@ bool Compiler::fgValueNumberConstLoad(GenTreeIndir* tree) } else if (funcApp.m_func == (VNFunc)GT_ADD) { - ssize_t dataOffset = 0; - ValueNum baseVN = ValueNumStore::NoVN; - - // Loop to accumulate total dataOffset, e.g.: - // ADD(C1, ADD(ObjHandle, C2)) -> C1 + C2 - do - { - ValueNum op1VN = funcApp.m_args[0]; - ValueNum op2VN = funcApp.m_args[1]; - - if (vnStore->IsVNConstant(op1VN) && varTypeIsIntegral(vnStore->TypeOfVN(op1VN)) && - !isCnsObjHandle(vnStore, op1VN, &objHandle)) - { - dataOffset += vnStore->CoercedConstantValue(op1VN); - baseVN = op2VN; - } - else if (vnStore->IsVNConstant(op2VN) && varTypeIsIntegral(vnStore->TypeOfVN(op2VN)) && - !isCnsObjHandle(vnStore, op2VN, &objHandle)) - { - dataOffset += vnStore->CoercedConstantValue(op2VN); - baseVN = op1VN; - } - else - { - // one of the args is expected to be an integer constant - return false; - } - } while (vnStore->GetVNFunc(baseVN, &funcApp) && (funcApp.m_func == (VNFunc)GT_ADD)); + target_ssize_t dataOffset = 0; + vnStore->PeelOffsets(&addrVN, &dataOffset); + ValueNum baseVN = addrVN; if (isCnsObjHandle(vnStore, baseVN, &objHandle) && (dataOffset >= (ssize_t)OFFSETOF__CORINFO_String__chars) && ((dataOffset % 2) == 0)) @@ -14434,67 +14395,27 @@ void Compiler::fgValueNumberAddExceptionSetForIndirection(GenTree* tree, GenTree ValueNumPair baseVNP = vnStore->VNPNormalPair(baseAddr->gtVNPair); ValueNum baseLVN = baseVNP.GetLiberal(); ValueNum baseCVN = baseVNP.GetConservative(); - ssize_t offsetL = 0; - ssize_t offsetC = 0; - VNFuncApp funcAttr; - while (vnStore->GetVNFunc(baseLVN, &funcAttr) && (funcAttr.m_func == (VNFunc)GT_ADD) && - (vnStore->TypeOfVN(baseLVN) == TYP_BYREF)) - { - // The arguments in value numbering functions are sorted in increasing order - // Thus either arg could be the constant. - if (vnStore->IsVNConstant(funcAttr.m_args[0]) && varTypeIsIntegral(vnStore->TypeOfVN(funcAttr.m_args[0]))) - { - offsetL += vnStore->CoercedConstantValue(funcAttr.m_args[0]); - baseLVN = funcAttr.m_args[1]; - } - else if (vnStore->IsVNConstant(funcAttr.m_args[1]) && varTypeIsIntegral(vnStore->TypeOfVN(funcAttr.m_args[1]))) - { - offsetL += vnStore->CoercedConstantValue(funcAttr.m_args[1]); - baseLVN = funcAttr.m_args[0]; - } - else // neither argument is a constant - { - break; - } + assert(baseVNP.BothDefined()); - if (fgIsBigOffset(offsetL)) - { - // Failure: Exit this loop if we have a "big" offset + target_ssize_t offsetL = 0; + target_ssize_t offsetC = 0; - // reset baseLVN back to the full address expression - baseLVN = baseVNP.GetLiberal(); - break; - } - } - - while (vnStore->GetVNFunc(baseCVN, &funcAttr) && (funcAttr.m_func == (VNFunc)GT_ADD) && - (vnStore->TypeOfVN(baseCVN) == TYP_BYREF)) + // baseAddr could be a SIMD for certain implicit indirs, e.g. GatherVector API. + if (!varTypeIsSIMD(baseAddr)) { - // The arguments in value numbering functions are sorted in increasing order - // Thus either arg could be the constant. - if (vnStore->IsVNConstant(funcAttr.m_args[0]) && varTypeIsIntegral(vnStore->TypeOfVN(funcAttr.m_args[0]))) - { - offsetL += vnStore->CoercedConstantValue(funcAttr.m_args[0]); - baseCVN = funcAttr.m_args[1]; - } - else if (vnStore->IsVNConstant(funcAttr.m_args[1]) && varTypeIsIntegral(vnStore->TypeOfVN(funcAttr.m_args[1]))) - { - offsetC += vnStore->CoercedConstantValue(funcAttr.m_args[1]); - baseCVN = funcAttr.m_args[0]; - } - else // neither argument is a constant + vnStore->PeelOffsets(&baseLVN, &offsetL); + if (fgIsBigOffset(offsetL)) { - break; + // Reset baseLVN back to the full address expression + baseLVN = baseVNP.GetLiberal(); } + vnStore->PeelOffsets(&baseCVN, &offsetC); if (fgIsBigOffset(offsetC)) { - // Failure: Exit this loop if we have a "big" offset - - // reset baseCVN back to the full address expression + // Reset baseCVN back to the full address expression baseCVN = baseVNP.GetConservative(); - break; } } @@ -15247,12 +15168,14 @@ void ValueNumStore::PeelOffsets(ValueNum* vn, target_ssize_t* offset) VNFuncApp app; while (GetVNFunc(*vn, &app) && (app.m_func == VNF_ADD)) { - if (IsVNConstantNonHandle(app.m_args[0])) + // We don't treat handles and null as constant offset. + + if (IsVNConstantNonHandle(app.m_args[0]) && (app.m_args[0] != VNForNull())) { *offset += ConstantValue(app.m_args[0]); *vn = app.m_args[1]; } - else if (IsVNConstantNonHandle(app.m_args[1])) + else if (IsVNConstantNonHandle(app.m_args[1]) && (app.m_args[1] != VNForNull())) { *offset += ConstantValue(app.m_args[1]); *vn = app.m_args[0];