@@ -4367,6 +4367,47 @@ GenTree* Compiler::optAssertionProp_RelOp(ASSERT_VALARG_TP assertions, GenTree*
43674367 return optAssertionPropLocal_RelOp (assertions, tree, stmt);
43684368}
43694369
4370+ // --------------------------------------------------------------------------------
4371+ // optVisitReachingAssertions: given a vn, call the specified callback function on all
4372+ // the assertions that reach it via PHI definitions if any.
4373+ //
4374+ // Arguments:
4375+ // vn - The vn to visit all the reaching assertions for
4376+ // argVisitor - The callback function to call on the vn and its reaching assertions
4377+ //
4378+ // Return Value:
4379+ // AssertVisit::Aborted - an argVisitor returned AssertVisit::Abort, we stop the walk and return
4380+ // AssertVisit::Continue - all argVisitor returned AssertVisit::Continue
4381+ //
4382+ template <typename TAssertVisitor>
4383+ Compiler::AssertVisit Compiler::optVisitReachingAssertions (ValueNum vn, TAssertVisitor argVisitor)
4384+ {
4385+ VNPhiDef phiDef;
4386+ if (!vnStore->GetPhiDef (vn, &phiDef))
4387+ {
4388+ // We assume that the caller already checked assertions for the current block, so we're
4389+ // interested only in assertions for PHI definitions.
4390+ return AssertVisit::Abort;
4391+ }
4392+
4393+ LclSsaVarDsc* ssaDef = lvaGetDesc (phiDef.LclNum )->GetPerSsaData (phiDef.SsaDef );
4394+ GenTreeLclVarCommon* node = ssaDef->GetDefNode ();
4395+ assert (node->IsPhiDefn ());
4396+
4397+ for (GenTreePhi::Use& use : node->Data ()->AsPhi ()->Uses ())
4398+ {
4399+ GenTreePhiArg* phiArg = use.GetNode ()->AsPhiArg ();
4400+ const ValueNum phiArgVN = vnStore->VNConservativeNormalValue (phiArg->gtVNPair );
4401+ ASSERT_TP assertions = optGetEdgeAssertions (ssaDef->GetBlock (), phiArg->gtPredBB );
4402+ if (argVisitor (phiArgVN, assertions) == AssertVisit::Abort)
4403+ {
4404+ // The visitor wants to abort the walk.
4405+ return AssertVisit::Abort;
4406+ }
4407+ }
4408+ return AssertVisit::Continue;
4409+ }
4410+
43704411// ------------------------------------------------------------------------
43714412// optAssertionProp: try and optimize a relop via assertion propagation
43724413//
@@ -4380,6 +4421,8 @@ GenTree* Compiler::optAssertionProp_RelOp(ASSERT_VALARG_TP assertions, GenTree*
43804421//
43814422GenTree* Compiler::optAssertionPropGlobal_RelOp (ASSERT_VALARG_TP assertions, GenTree* tree, Statement* stmt)
43824423{
4424+ assert (!optLocalAssertionProp);
4425+
43834426 GenTree* newTree = tree;
43844427 GenTree* op1 = tree->AsOp ()->gtOp1 ;
43854428 GenTree* op2 = tree->AsOp ()->gtOp2 ;
@@ -4463,6 +4506,24 @@ GenTree* Compiler::optAssertionPropGlobal_RelOp(ASSERT_VALARG_TP assertions, Gen
44634506 return nullptr ;
44644507 }
44654508
4509+ // See if we have "PHI ==/!= null" tree. If so, we iterate over all PHI's arguments,
4510+ // and if all of them are known to be non-null, we can bash the comparison to true/false.
4511+ if (op2->IsIntegralConst (0 ) && op1->TypeIs (TYP_REF))
4512+ {
4513+ auto visitor = [this ](ValueNum reachingVN, ASSERT_TP reachingAssertions) {
4514+ return optAssertionVNIsNonNull (reachingVN, reachingAssertions) ? AssertVisit::Continue : AssertVisit::Abort;
4515+ };
4516+
4517+ ValueNum op1vn = vnStore->VNConservativeNormalValue (op1->gtVNPair );
4518+ if (optVisitReachingAssertions (op1vn, visitor) == AssertVisit::Continue)
4519+ {
4520+ JITDUMP (" ... all of PHI's arguments are never null!\n " );
4521+ assert (newTree->OperIs (GT_EQ, GT_NE));
4522+ newTree = tree->OperIs (GT_EQ) ? gtNewIconNode (0 ) : gtNewIconNode (1 );
4523+ return optAssertionProp_Update (newTree, tree, stmt);
4524+ }
4525+ }
4526+
44664527 // Find an equal or not equal assertion involving "op1" and "op2".
44674528 index = optGlobalAssertionIsEqualOrNotEqual (assertions, op1, op2);
44684529
@@ -5083,31 +5144,19 @@ bool Compiler::optAssertionVNIsNonNull(ValueNum vn, ASSERT_VALARG_TP assertions)
50835144 return true ;
50845145 }
50855146
5086- // Check each assertion to find if we have a vn != null assertion.
5087- //
5088- BitVecOps::Iter iter (apTraits, assertions);
5089- unsigned index = 0 ;
5090- while (iter.NextElem (&index))
5147+ if (!BitVecOps::MayBeUninit (assertions))
50915148 {
5092- AssertionIndex assertionIndex = GetAssertionIndex (index);
5093- if (assertionIndex > optAssertionCount)
5094- {
5095- break ;
5096- }
5097- AssertionDsc* curAssertion = optGetAssertion (assertionIndex);
5098- if (!curAssertion->CanPropNonNull ())
5099- {
5100- continue ;
5101- }
5102-
5103- if (curAssertion->op1 .vn != vn)
5149+ BitVecOps::Iter iter (apTraits, assertions);
5150+ unsigned index = 0 ;
5151+ while (iter.NextElem (&index))
51045152 {
5105- continue ;
5153+ AssertionDsc* curAssertion = optGetAssertion (GetAssertionIndex (index));
5154+ if (curAssertion->CanPropNonNull () && curAssertion->op1 .vn == vn)
5155+ {
5156+ return true ;
5157+ }
51065158 }
5107-
5108- return true ;
51095159 }
5110-
51115160 return false ;
51125161}
51135162
@@ -5810,6 +5859,30 @@ ASSERT_VALRET_TP Compiler::optGetVnMappedAssertions(ValueNum vn)
58105859 return BitVecOps::UninitVal ();
58115860}
58125861
5862+ // ------------------------------------------------------------------------
5863+ // optGetEdgeAssertions: Given a block and its predecessor, get the assertions
5864+ // the predecessor creates for the block.
5865+ //
5866+ // Arguments:
5867+ // block - The block to get the assertions for.
5868+ // blockPred - The predecessor of the block (creating the assertions).
5869+ //
5870+ // Return Value:
5871+ // The assertions we have about the value number.
5872+ //
5873+ ASSERT_VALRET_TP Compiler::optGetEdgeAssertions (const BasicBlock* block, const BasicBlock* blockPred) const
5874+ {
5875+ if ((blockPred->KindIs (BBJ_COND) && blockPred->TrueTargetIs (block)))
5876+ {
5877+ if (bbJtrueAssertionOut != nullptr )
5878+ {
5879+ return bbJtrueAssertionOut[blockPred->bbNum ];
5880+ }
5881+ return BitVecOps::MakeEmpty (apTraits);
5882+ }
5883+ return blockPred->bbAssertionOut ;
5884+ }
5885+
58135886/* ****************************************************************************
58145887 *
58155888 * Given a const assertion this method computes the set of implied assertions
0 commit comments