diff --git a/src/jit/assertionprop.cpp b/src/jit/assertionprop.cpp index 73d6b8c9d881..ac6f5c4a2976 100644 --- a/src/jit/assertionprop.cpp +++ b/src/jit/assertionprop.cpp @@ -2963,12 +2963,24 @@ AssertionIndex Compiler::optLocalAssertionIsEqualOrNotEqual( return NO_ASSERTION_INDEX; } -/***************************************************************************** - * - * Given a set of "assertions" to search for, find an assertion that is either - * "op1" == "op2" or "op1" != "op2." Does a value number based comparison. - * - */ +//------------------------------------------------------------------------ +// optGlobalAssertionIsEqualOrNotEqual: Look for an assertion in the specified +// set that is one of op1 == op1, op1 != op2, or *op1 == op2, +// where equality is based on value numbers. +// +// Arguments: +// assertions: bit vector describing set of assertions +// op1, op2: the treen nodes in question +// +// Returns: +// Index of first matching assertion, or NO_ASSERTION_INDEX if no +// assertions in the set are matches. +// +// Notes: +// Assertions based on *op1 are the result of exact type tests and are +// only returned when op1 is a local var with ref type and the assertion +// is an exact type equality. +// AssertionIndex Compiler::optGlobalAssertionIsEqualOrNotEqual(ASSERT_VALARG_TP assertions, GenTree* op1, GenTree* op2) { if (BitVecOps::IsEmpty(apTraits, assertions)) @@ -2995,6 +3007,23 @@ AssertionIndex Compiler::optGlobalAssertionIsEqualOrNotEqual(ASSERT_VALARG_TP as { return assertionIndex; } + + // Look for matching exact type assertions based on vtable accesses + if ((curAssertion->assertionKind == OAK_EQUAL) && (curAssertion->op1.kind == O1K_EXACT_TYPE) && + op1->OperIs(GT_IND)) + { + GenTree* indirAddr = op1->AsIndir()->Addr(); + + if (indirAddr->OperIs(GT_LCL_VAR) && (indirAddr->TypeGet() == TYP_REF)) + { + // op1 is accessing vtable of a ref type local var + if ((curAssertion->op1.vn == vnStore->VNConservativeNormalValue(indirAddr->gtVNPair)) && + (curAssertion->op2.vn == vnStore->VNConservativeNormalValue(op2->gtVNPair))) + { + return assertionIndex; + } + } + } } return NO_ASSERTION_INDEX; } @@ -3119,13 +3148,19 @@ GenTree* Compiler::optAssertionPropGlobal_RelOp(ASSERT_VALARG_TP assertions, Gen return optAssertionProp_Update(newTree, tree, stmt); } - // Else check if we have an equality check involving a local + // Else check if we have an equality check involving a local or an indir if (!tree->OperIs(GT_EQ, GT_NE)) { return nullptr; } - if (op1->gtOper != GT_LCL_VAR) + // Bail out if tree is not side effect free. + if ((tree->gtFlags & GTF_SIDE_EFFECT) != 0) + { + return nullptr; + } + + if (!op1->OperIs(GT_LCL_VAR, GT_IND)) { return nullptr; } @@ -3188,11 +3223,21 @@ GenTree* Compiler::optAssertionPropGlobal_RelOp(ASSERT_VALARG_TP assertions, Gen { op1->ChangeOperConst(GT_CNS_INT); op1->AsIntCon()->gtIconVal = vnStore->ConstantValue(vnCns); + + if (vnStore->IsVNHandle(vnCns)) + { + op1->gtFlags |= (vnStore->GetHandleFlags(vnCns) & GTF_ICON_HDL_MASK); + } } else if (op1->TypeGet() == TYP_LONG) { op1->ChangeOperConst(GT_CNS_NATIVELONG); op1->AsIntConCommon()->SetLngValue(vnStore->ConstantValue(vnCns)); + + if (vnStore->IsVNHandle(vnCns)) + { + op1->gtFlags |= (vnStore->GetHandleFlags(vnCns) & GTF_ICON_HDL_MASK); + } } else if (op1->TypeGet() == TYP_DOUBLE) { @@ -3227,6 +3272,16 @@ GenTree* Compiler::optAssertionPropGlobal_RelOp(ASSERT_VALARG_TP assertions, Gen } op1->gtVNPair.SetBoth(vnCns); // Preserve the ValueNumPair, as ChangeOperConst/SetOper will clear it. + + // Also set the value number on the relop. + if (curAssertion->assertionKind == OAK_EQUAL) + { + tree->gtVNPair.SetBoth(vnStore->VNOneForType(TYP_INT)); + } + else + { + tree->gtVNPair.SetBoth(vnStore->VNZeroForType(TYP_INT)); + } } // If the assertion involves "op2" and "op1" is also a local var, then just morph the tree. else if (op2->gtOper == GT_LCL_VAR) @@ -3957,7 +4012,7 @@ GenTree* Compiler::optAssertionProp_Update(GenTree* newTree, GenTree* tree, Stat * Returns the modified tree, or nullptr if no assertion prop took place. */ -GenTree* Compiler::optAssertionProp(ASSERT_VALARG_TP assertions, GenTree* tree, Statement* stmt) +GenTree* Compiler::optAssertionProp(ASSERT_VALARG_TP assertions, GenTree* tree, Statement* stmt, BasicBlock* block) { switch (tree->gtOper) { @@ -3992,6 +4047,14 @@ GenTree* Compiler::optAssertionProp(ASSERT_VALARG_TP assertions, GenTree* tree, return optAssertionProp_RelOp(assertions, tree, stmt); + case GT_JTRUE: + + if (block != nullptr) + { + return optVNConstantPropOnJTrue(block, tree); + } + return nullptr; + default: return nullptr; } @@ -5153,18 +5216,11 @@ void Compiler::optAssertionPropMain() // and thus we must morph, set order, re-link for (GenTree* tree = stmt->GetTreeList(); tree != nullptr; tree = tree->gtNext) { - if (tree->OperIs(GT_JTRUE)) - { - // A GT_TRUE is always the last node in a tree, so we can break here - assert((tree->gtNext == nullptr) && (stmt->GetNextStmt() == nullptr)); - break; - } - JITDUMP("Propagating %s assertions for " FMT_BB ", stmt " FMT_STMT ", tree [%06d], tree -> %d\n", BitVecOps::ToString(apTraits, assertions), block->bbNum, stmt->GetID(), dspTreeID(tree), tree->GetAssertionInfo().GetAssertionIndex()); - GenTree* newTree = optAssertionProp(assertions, tree, stmt); + GenTree* newTree = optAssertionProp(assertions, tree, stmt, block); if (newTree) { assert(optAssertionPropagatedCurrentStmt == true); diff --git a/src/jit/compiler.h b/src/jit/compiler.h index d989863b0e9c..7646ddd1dc58 100644 --- a/src/jit/compiler.h +++ b/src/jit/compiler.h @@ -6730,7 +6730,7 @@ class Compiler Statement* stmt DEBUGARG(AssertionIndex index)); // Assertion propagation functions. - GenTree* optAssertionProp(ASSERT_VALARG_TP assertions, GenTree* tree, Statement* stmt); + GenTree* optAssertionProp(ASSERT_VALARG_TP assertions, GenTree* tree, Statement* stmt, BasicBlock* block); GenTree* optAssertionProp_LclVar(ASSERT_VALARG_TP assertions, GenTree* tree, Statement* stmt); GenTree* optAssertionProp_Ind(ASSERT_VALARG_TP assertions, GenTree* tree, Statement* stmt); GenTree* optAssertionProp_Cast(ASSERT_VALARG_TP assertions, GenTree* tree, Statement* stmt); diff --git a/src/jit/morph.cpp b/src/jit/morph.cpp index 6198230708fd..83ded74db6b6 100644 --- a/src/jit/morph.cpp +++ b/src/jit/morph.cpp @@ -14444,7 +14444,7 @@ GenTree* Compiler::fgMorphTree(GenTree* tree, MorphAddrContext* mac) { tree = newTree; /* newTree is non-Null if we propagated an assertion */ - newTree = optAssertionProp(apFull, tree, nullptr); + newTree = optAssertionProp(apFull, tree, nullptr, nullptr); } assert(tree != nullptr); }