Changes to use VNNormalValue in assertionProp
authorBrian Sullivan <briansul@microsoft.com>
Mon, 17 Sep 2018 20:39:18 +0000 (13:39 -0700)
committerBrian Sullivan <briansul@microsoft.com>
Wed, 19 Sep 2018 18:07:02 +0000 (11:07 -0700)
Commit migrated from https://github.com/dotnet/coreclr/commit/8797f7a36aec5df957f28e4c9e09c22cc5fe5484

src/coreclr/src/jit/assertionprop.cpp
src/coreclr/src/jit/rangecheck.cpp
src/coreclr/src/jit/valuenum.cpp
src/coreclr/src/jit/valuenum.h

index 8bc83fe..ebcbf95 100644 (file)
@@ -856,8 +856,8 @@ AssertionIndex Compiler::optCreateAssertion(GenTree*         op1,
             GenTreeBoundsChk* arrBndsChk = op1->AsBoundsChk();
             assertion->assertionKind     = assertionKind;
             assertion->op1.kind          = O1K_ARR_BND;
-            assertion->op1.bnd.vnIdx     = arrBndsChk->gtIndex->gtVNPair.GetConservative();
-            assertion->op1.bnd.vnLen     = arrBndsChk->gtArrLen->gtVNPair.GetConservative();
+            assertion->op1.bnd.vnIdx     = vnStore->VNNormalValue(arrBndsChk->gtIndex->gtVNPair, VNK_Conservative);
+            assertion->op1.bnd.vnLen     = vnStore->VNNormalValue(arrBndsChk->gtArrLen->gtVNPair, VNK_Conservative);
             goto DONE_ASSERTION;
         }
     }
@@ -932,7 +932,7 @@ AssertionIndex Compiler::optCreateAssertion(GenTree*         op1,
                 goto DONE_ASSERTION; // Don't make an assertion
             }
 
-            vn = op1->gtVNPair.GetConservative();
+            vn = vnStore->VNNormalValue(op1->gtVNPair, VNK_Conservative);
             VNFuncApp funcAttr;
 
             // Try to get value number corresponding to the GC ref of the indirection
@@ -975,7 +975,7 @@ AssertionIndex Compiler::optCreateAssertion(GenTree*         op1,
             assertion->op1.kind       = O1K_LCLVAR;
             assertion->op1.lcl.lclNum = lclNum;
             assertion->op1.lcl.ssaNum = op1->AsLclVarCommon()->GetSsaNum();
-            vn                        = op1->gtVNPair.GetConservative();
+            vn                        = vnStore->VNNormalValue(op1->gtVNPair, VNK_Conservative);
         }
 
         assertion->op1.vn           = vn;
@@ -1036,10 +1036,10 @@ AssertionIndex Compiler::optCreateAssertion(GenTree*         op1,
             //
             assertion->op1.kind         = O1K_SUBTYPE;
             assertion->op1.lcl.lclNum   = lclNum;
-            assertion->op1.vn           = op1->gtVNPair.GetConservative();
+            assertion->op1.vn           = vnStore->VNNormalValue(op1->gtVNPair, VNK_Conservative);
             assertion->op1.lcl.ssaNum   = op1->AsLclVarCommon()->GetSsaNum();
             assertion->op2.u1.iconVal   = op2->gtIntCon.gtIconVal;
-            assertion->op2.vn           = op2->gtVNPair.GetConservative();
+            assertion->op2.vn           = vnStore->VNNormalValue(op2->gtVNPair, VNK_Conservative);
             assertion->op2.u1.iconFlags = op2->GetIconHandleFlag();
 
             //
@@ -1057,7 +1057,7 @@ AssertionIndex Compiler::optCreateAssertion(GenTree*         op1,
 
             assertion->op1.kind       = O1K_LCLVAR;
             assertion->op1.lcl.lclNum = lclNum;
-            assertion->op1.vn         = op1->gtVNPair.GetConservative();
+            assertion->op1.vn         = vnStore->VNNormalValue(op1->gtVNPair, VNK_Conservative);
             assertion->op1.lcl.ssaNum = op1->AsLclVarCommon()->GetSsaNum();
 
             switch (op2->gtOper)
@@ -1104,7 +1104,7 @@ AssertionIndex Compiler::optCreateAssertion(GenTree*         op1,
 
                     assertion->op2.kind    = op2Kind;
                     assertion->op2.lconVal = 0;
-                    assertion->op2.vn      = op2->gtVNPair.GetConservative();
+                    assertion->op2.vn      = vnStore->VNNormalValue(op2->gtVNPair, VNK_Conservative);
 
                     if (op2->gtOper == GT_CNS_INT)
                     {
@@ -1190,7 +1190,7 @@ AssertionIndex Compiler::optCreateAssertion(GenTree*         op1,
 
                     assertion->op2.kind       = O2K_LCLVAR_COPY;
                     assertion->op2.lcl.lclNum = lclNum2;
-                    assertion->op2.vn         = op2->gtVNPair.GetConservative();
+                    assertion->op2.vn         = vnStore->VNNormalValue(op2->gtVNPair, VNK_Conservative);
                     assertion->op2.lcl.ssaNum = op2->AsLclVarCommon()->GetSsaNum();
 
                     //
@@ -1319,11 +1319,13 @@ AssertionIndex Compiler::optCreateAssertion(GenTree*         op1,
 
             assertion->op1.kind       = O1K_EXACT_TYPE;
             assertion->op1.lcl.lclNum = lclNum;
-            assertion->op1.vn         = op1->gtVNPair.GetConservative();
+            assertion->op1.vn         = vnStore->VNNormalValue(op1->gtVNPair, VNK_Conservative);
             assertion->op1.lcl.ssaNum = op1->AsLclVarCommon()->GetSsaNum();
+
             assert(assertion->op1.lcl.ssaNum == SsaConfig::RESERVED_SSA_NUM ||
                    assertion->op1.vn ==
-                       lvaTable[lclNum].GetPerSsaData(assertion->op1.lcl.ssaNum)->m_vnPair.GetConservative());
+                       vnStore->VNNormalValue(lvaTable[lclNum].GetPerSsaData(assertion->op1.lcl.ssaNum)->m_vnPair,
+                                              VNK_Conservative));
 
             ssize_t  cnsValue  = 0;
             unsigned iconFlags = 0;
@@ -1338,7 +1340,8 @@ AssertionIndex Compiler::optCreateAssertion(GenTree*         op1,
                 assertion->assertionKind  = assertionKind;
                 assertion->op2.kind       = O2K_IND_CNS_INT;
                 assertion->op2.u1.iconVal = cnsValue;
-                assertion->op2.vn         = op2->gtOp.gtOp1->gtVNPair.GetConservative();
+                assertion->op2.vn         = vnStore->VNNormalValue(op2->gtOp.gtOp1->gtVNPair, VNK_Conservative);
+
                 /* iconFlags should only contain bits in GTF_ICON_HDL_MASK */
                 assert((iconFlags & ~GTF_ICON_HDL_MASK) == 0);
                 assertion->op2.u1.iconFlags = iconFlags;
@@ -1355,7 +1358,8 @@ AssertionIndex Compiler::optCreateAssertion(GenTree*         op1,
                 assertion->assertionKind  = assertionKind;
                 assertion->op2.kind       = O2K_IND_CNS_INT;
                 assertion->op2.u1.iconVal = cnsValue;
-                assertion->op2.vn         = op2->gtVNPair.GetConservative();
+                assertion->op2.vn         = vnStore->VNNormalValue(op2->gtVNPair, VNK_Conservative);
+
                 /* iconFlags should only contain bits in GTF_ICON_HDL_MASK */
                 assert((iconFlags & ~GTF_ICON_HDL_MASK) == 0);
                 assertion->op2.u1.iconFlags = iconFlags;
@@ -1432,12 +1436,14 @@ bool Compiler::optIsTreeKnownIntValue(bool vnBased, GenTree* tree, ssize_t* pCon
     }
 
     // Global assertion prop
-    if (!vnStore->IsVNConstant(tree->gtVNPair.GetConservative()))
+    ValueNum vn = vnStore->VNNormalValue(tree->gtVNPair, VNK_Conservative);
+    if (!vnStore->IsVNConstant(vn))
     {
         return false;
     }
 
-    ValueNum  vn     = tree->gtVNPair.GetConservative();
+    // ValueNumber 'vn' indicates that this node evaluates to a constant
+
     var_types vnType = vnStore->TypeOfVN(vn);
     if (vnType == TYP_INT)
     {
@@ -1762,20 +1768,23 @@ AssertionInfo Compiler::optCreateJTrueBoundsAssertion(GenTree* tree)
     GenTree* op1 = relop->gtGetOp1();
     GenTree* op2 = relop->gtGetOp2();
 
-    ValueNum vn = op1->gtVNPair.GetConservative();
+    ValueNum op1VN   = vnStore->VNNormalValue(op1->gtVNPair, VNK_Conservative);
+    ValueNum op2VN   = vnStore->VNNormalValue(op2->gtVNPair, VNK_Conservative);
+    ValueNum relopVN = vnStore->VNNormalValue(relop->gtVNPair, VNK_Conservative);
+
+    bool hasTestAgainstZero =
+        (relop->gtOper == GT_EQ || relop->gtOper == GT_NE) && (op2VN == vnStore->VNZeroForType(op2->TypeGet()));
 
     ValueNumStore::UnsignedCompareCheckedBoundInfo unsignedCompareBnd;
     // Cases where op1 holds the upper bound arithmetic and op2 is 0.
     // Loop condition like: "i < bnd +/-k == 0"
     // Assertion: "i < bnd +/- k == 0"
-    if (vnStore->IsVNCompareCheckedBoundArith(vn) &&
-        op2->gtVNPair.GetConservative() == vnStore->VNZeroForType(op2->TypeGet()) &&
-        (relop->gtOper == GT_EQ || relop->gtOper == GT_NE))
+    if (hasTestAgainstZero && vnStore->IsVNCompareCheckedBoundArith(op1VN))
     {
         AssertionDsc dsc;
         dsc.assertionKind    = relop->gtOper == GT_EQ ? OAK_EQUAL : OAK_NOT_EQUAL;
         dsc.op1.kind         = O1K_BOUND_OPER_BND;
-        dsc.op1.vn           = vn;
+        dsc.op1.vn           = op1VN;
         dsc.op2.kind         = O2K_CONST_INT;
         dsc.op2.vn           = vnStore->VNZeroForType(op2->TypeGet());
         dsc.op2.u1.iconVal   = 0;
@@ -1787,14 +1796,12 @@ AssertionInfo Compiler::optCreateJTrueBoundsAssertion(GenTree* tree)
     // Cases where op1 holds the upper bound and op2 is 0.
     // Loop condition like: "i < bnd == 0"
     // Assertion: "i < bnd == false"
-    else if (vnStore->IsVNCompareCheckedBound(vn) &&
-             (op2->gtVNPair.GetConservative() == vnStore->VNZeroForType(op2->TypeGet())) &&
-             (relop->gtOper == GT_EQ || relop->gtOper == GT_NE))
+    else if (hasTestAgainstZero && vnStore->IsVNCompareCheckedBound(op1VN))
     {
         AssertionDsc dsc;
         dsc.assertionKind    = relop->gtOper == GT_EQ ? OAK_EQUAL : OAK_NOT_EQUAL;
         dsc.op1.kind         = O1K_BOUND_LOOP_BND;
-        dsc.op1.vn           = vn;
+        dsc.op1.vn           = op1VN;
         dsc.op2.kind         = O2K_CONST_INT;
         dsc.op2.vn           = vnStore->VNZeroForType(op2->TypeGet());
         dsc.op2.u1.iconVal   = 0;
@@ -1806,12 +1813,12 @@ AssertionInfo Compiler::optCreateJTrueBoundsAssertion(GenTree* tree)
     // Cases where op1 holds the lhs of the condition op2 holds the bound.
     // Loop condition like "i < bnd"
     // Assertion: "i < bnd != 0"
-    else if (vnStore->IsVNCompareCheckedBound(relop->gtVNPair.GetConservative()))
+    else if (vnStore->IsVNCompareCheckedBound(relopVN))
     {
         AssertionDsc dsc;
         dsc.assertionKind    = OAK_NOT_EQUAL;
         dsc.op1.kind         = O1K_BOUND_LOOP_BND;
-        dsc.op1.vn           = relop->gtVNPair.GetConservative();
+        dsc.op1.vn           = relopVN;
         dsc.op2.kind         = O2K_CONST_INT;
         dsc.op2.vn           = vnStore->VNZeroForType(TYP_INT);
         dsc.op2.u1.iconVal   = 0;
@@ -1822,7 +1829,7 @@ AssertionInfo Compiler::optCreateJTrueBoundsAssertion(GenTree* tree)
     }
     // Loop condition like "(uint)i < (uint)bnd" or equivalent
     // Assertion: "no throw" since this condition guarantees that i is both >= 0 and < bnd (on the appropiate edge)
-    else if (vnStore->IsVNUnsignedCompareCheckedBound(relop->gtVNPair.GetConservative(), &unsignedCompareBnd))
+    else if (vnStore->IsVNUnsignedCompareCheckedBound(relopVN, &unsignedCompareBnd))
     {
         assert(unsignedCompareBnd.vnIdx != ValueNumStore::NoVN);
         assert((unsignedCompareBnd.cmpOper == VNF_LT_UN) || (unsignedCompareBnd.cmpOper == VNF_GE_UN));
@@ -1831,9 +1838,9 @@ AssertionInfo Compiler::optCreateJTrueBoundsAssertion(GenTree* tree)
         AssertionDsc dsc;
         dsc.assertionKind = OAK_NO_THROW;
         dsc.op1.kind      = O1K_ARR_BND;
-        dsc.op1.vn        = relop->gtVNPair.GetConservative();
+        dsc.op1.vn        = relopVN;
         dsc.op1.bnd.vnIdx = unsignedCompareBnd.vnIdx;
-        dsc.op1.bnd.vnLen = unsignedCompareBnd.vnBound;
+        dsc.op1.bnd.vnLen = vnStore->VNNormalValue(unsignedCompareBnd.vnBound);
         dsc.op2.kind      = O2K_INVALID;
         dsc.op2.vn        = ValueNumStore::NoVN;
 
@@ -1849,14 +1856,12 @@ AssertionInfo Compiler::optCreateJTrueBoundsAssertion(GenTree* tree)
     // Cases where op1 holds the condition bound check and op2 is 0.
     // Loop condition like: "i < 100 == 0"
     // Assertion: "i < 100 == false"
-    else if (vnStore->IsVNConstantBound(vn) &&
-             (op2->gtVNPair.GetConservative() == vnStore->VNZeroForType(op2->TypeGet())) &&
-             (relop->gtOper == GT_EQ || relop->gtOper == GT_NE))
+    else if (hasTestAgainstZero && vnStore->IsVNConstantBound(op1VN))
     {
         AssertionDsc dsc;
         dsc.assertionKind    = relop->gtOper == GT_EQ ? OAK_EQUAL : OAK_NOT_EQUAL;
         dsc.op1.kind         = O1K_CONSTANT_LOOP_BND;
-        dsc.op1.vn           = vn;
+        dsc.op1.vn           = op1VN;
         dsc.op2.kind         = O2K_CONST_INT;
         dsc.op2.vn           = vnStore->VNZeroForType(op2->TypeGet());
         dsc.op2.u1.iconVal   = 0;
@@ -1868,12 +1873,12 @@ AssertionInfo Compiler::optCreateJTrueBoundsAssertion(GenTree* tree)
     // Cases where op1 holds the lhs of the condition op2 holds rhs.
     // Loop condition like "i < 100"
     // Assertion: "i < 100 != 0"
-    else if (vnStore->IsVNConstantBound(relop->gtVNPair.GetConservative()))
+    else if (vnStore->IsVNConstantBound(relopVN))
     {
         AssertionDsc dsc;
         dsc.assertionKind    = OAK_NOT_EQUAL;
         dsc.op1.kind         = O1K_CONSTANT_LOOP_BND;
-        dsc.op1.vn           = relop->gtVNPair.GetConservative();
+        dsc.op1.vn           = relopVN;
         dsc.op2.kind         = O2K_CONST_INT;
         dsc.op2.vn           = vnStore->VNZeroForType(TYP_INT);
         dsc.op2.u1.iconVal   = 0;
@@ -2217,8 +2222,9 @@ AssertionIndex Compiler::optAssertionIsSubrange(GenTree* tree, var_types toType,
             (curAssertion->op1.kind == O1K_LCLVAR))
         {
             // For local assertion prop use comparison on locals, and use comparison on vns for global prop.
-            bool isEqual = optLocalAssertionProp ? (curAssertion->op1.lcl.lclNum == tree->AsLclVarCommon()->GetLclNum())
-                                                 : (curAssertion->op1.vn == tree->gtVNPair.GetConservative());
+            bool isEqual = optLocalAssertionProp
+                               ? (curAssertion->op1.lcl.lclNum == tree->AsLclVarCommon()->GetLclNum())
+                               : (curAssertion->op1.vn == vnStore->VNNormalValue(tree->gtVNPair, VNK_Conservative));
             if (!isEqual)
             {
                 continue;
@@ -2287,8 +2293,9 @@ AssertionIndex Compiler::optAssertionIsSubtype(GenTree* tree, GenTree* methodTab
         }
 
         // If local assertion prop use "lcl" based comparison, if global assertion prop use vn based comparison.
-        if ((optLocalAssertionProp) ? (curAssertion->op1.lcl.lclNum != tree->AsLclVarCommon()->GetLclNum())
-                                    : (curAssertion->op1.vn != tree->gtVNPair.GetConservative()))
+        if ((optLocalAssertionProp)
+                ? (curAssertion->op1.lcl.lclNum != tree->AsLclVarCommon()->GetLclNum())
+                : (curAssertion->op1.vn != vnStore->VNNormalValue(tree->gtVNPair, VNK_Conservative)))
         {
             continue;
         }
@@ -2368,8 +2375,9 @@ GenTree* Compiler::optVNConstantPropOnTree(BasicBlock* block, GenTree* stmt, Gen
         return nullptr;
     }
 
-    ValueNum vnCns = tree->gtVNPair.GetConservative();
-    ValueNum vnLib = tree->gtVNPair.GetLiberal();
+    // We want to use the Normal ValueNumber when checking for constants.
+    ValueNum vnCns = vnStore->VNNormalValue(tree->gtVNPair, VNK_Conservative);
+    ValueNum vnLib = vnStore->VNNormalValue(tree->gtVNPair, VNK_Liberal);
 
     // Check if node evaluates to a constant.
     if (!vnStore->IsVNConstant(vnCns))
@@ -2889,7 +2897,7 @@ GenTree* Compiler::optAssertionProp_LclVar(ASSERT_VALARG_TP assertions, GenTree*
                 return optConstantAssertionProp(curAssertion, tree, stmt DEBUGARG(assertionIndex));
             }
             // If global assertion, perform constant propagation only if the VN's match and the lcl is non-CSE.
-            else if (curAssertion->op1.vn == tree->gtVNPair.GetConservative())
+            else if (curAssertion->op1.vn == vnStore->VNNormalValue(tree->gtVNPair, VNK_Conservative))
             {
 #if FEATURE_ANYCSE
                 // Don't perform constant prop for CSE LclVars
@@ -2973,8 +2981,8 @@ AssertionIndex Compiler::optGlobalAssertionIsEqualOrNotEqual(ASSERT_VALARG_TP as
             continue;
         }
 
-        if (curAssertion->op1.vn == op1->gtVNPair.GetConservative() &&
-            curAssertion->op2.vn == op2->gtVNPair.GetConservative())
+        if ((curAssertion->op1.vn == vnStore->VNNormalValue(op1->gtVNPair, VNK_Conservative)) &&
+            (curAssertion->op2.vn == vnStore->VNNormalValue(op2->gtVNPair, VNK_Conservative)))
         {
             return assertionIndex;
         }
@@ -3046,9 +3054,9 @@ GenTree* Compiler::optAssertionPropGlobal_RelOp(ASSERT_VALARG_TP assertions, Gen
     bool allowReverse = true;
 
     // If the assertion involves "op2" and it is a constant, then check if "op1" also has a constant value.
-    if (vnStore->IsVNConstant(op2->gtVNPair.GetConservative()))
+    ValueNum vnCns = vnStore->VNNormalValue(op2->gtVNPair, VNK_Conservative);
+    if (vnStore->IsVNConstant(vnCns))
     {
-        ValueNum vnCns = op2->gtVNPair.GetConservative();
 #ifdef DEBUG
         if (verbose)
         {
@@ -3709,9 +3717,9 @@ GenTree* Compiler::optAssertionProp_BndsChk(ASSERT_VALARG_TP assertions, GenTree
 #endif
 
         // Do we have a previous range check involving the same 'vnLen' upper bound?
-        if (curAssertion->op1.bnd.vnLen == arrBndsChk->gtArrLen->gtVNPair.GetConservative())
+        if (curAssertion->op1.bnd.vnLen == vnStore->VNNormalValue(arrBndsChk->gtArrLen->gtVNPair, VNK_Conservative))
         {
-            ValueNum vnCurIdx = arrBndsChk->gtIndex->gtVNPair.GetConservative();
+            ValueNum vnCurIdx = vnStore->VNNormalValue(arrBndsChk->gtIndex->gtVNPair, VNK_Conservative);
 
             // Do we have the exact same lower bound 'vnIdx'?
             //       a[i] followed by a[i]
@@ -4605,7 +4613,7 @@ GenTree* Compiler::optPrepareTreeForReplacement(GenTree* oldTree, GenTree* newTr
             // (e.g. VN may evaluate a DIV/MOD node to a constant and the node may still
             // have GTF_EXCEPT set, even if it does not actually throw any exceptions).
             assert(!gtNodeHasSideEffects(oldTree, GTF_EXCEPT) ||
-                   vnStore->IsVNConstant(oldTree->gtVNPair.GetConservative()));
+                   vnStore->IsVNConstant(vnStore->VNNormalValue(oldTree->gtVNPair, VNK_Conservative)));
 
             ignoreRoot = true;
         }
@@ -4678,7 +4686,9 @@ GenTree* Compiler::optVNConstantPropOnJTrue(BasicBlock* block, GenTree* stmt, Ge
     //
     assert((relop->gtFlags & GTF_RELOP_JMP_USED) != 0);
 
-    if (!vnStore->IsVNConstant(relop->gtVNPair.GetConservative()))
+    ValueNum vnCns = relop->gtVNPair.GetConservative();
+    ValueNum vnLib = relop->gtVNPair.GetLiberal();
+    if (!vnStore->IsVNConstant(vnCns))
     {
         return nullptr;
     }
@@ -4694,9 +4704,7 @@ GenTree* Compiler::optVNConstantPropOnJTrue(BasicBlock* block, GenTree* stmt, Ge
     relop->gtOp.gtOp2->gtVNPair = ValueNumPair(vnZero, vnZero);
 
     // Update the oper and restore the value numbers.
-    ValueNum vnCns       = relop->gtVNPair.GetConservative();
-    ValueNum vnLib       = relop->gtVNPair.GetLiberal();
-    bool     evalsToTrue = (vnStore->CoercedConstantValue<INT64>(vnCns) != 0);
+    bool evalsToTrue = (vnStore->CoercedConstantValue<INT64>(vnCns) != 0);
     relop->SetOper(evalsToTrue ? GT_EQ : GT_NE);
     relop->gtVNPair = ValueNumPair(vnLib, vnCns);
 
index 3887b2f..95a007c 100644 (file)
@@ -75,7 +75,7 @@ bool RangeCheck::BetweenBounds(Range& range, int lower, GenTree* upper)
     ValueNumStore* vnStore = m_pCompiler->vnStore;
 
     // Get the VN for the upper limit.
-    ValueNum uLimitVN = upper->gtVNPair.GetConservative();
+    ValueNum uLimitVN = vnStore->VNNormalValue(upper->gtVNPair, VNK_Conservative);
 
 #ifdef DEBUG
     JITDUMP(FMT_VN " upper bound is: ", uLimitVN);
@@ -208,8 +208,8 @@ void RangeCheck::OptimizeRangeCheck(BasicBlock* block, GenTree* stmt, GenTree* t
     GenTree* treeIndex        = bndsChk->gtIndex;
 
     // Take care of constant index first, like a[2], for example.
-    ValueNum idxVn    = treeIndex->gtVNPair.GetConservative();
-    ValueNum arrLenVn = bndsChk->gtArrLen->gtVNPair.GetConservative();
+    ValueNum idxVn    = m_pCompiler->vnStore->VNNormalValue(treeIndex->gtVNPair, VNK_Conservative);
+    ValueNum arrLenVn = m_pCompiler->vnStore->VNNormalValue(bndsChk->gtArrLen->gtVNPair, VNK_Conservative);
     int      arrSize  = 0;
 
     if (m_pCompiler->vnStore->IsVNConstant(arrLenVn))
@@ -540,6 +540,9 @@ void RangeCheck::MergeEdgeAssertions(GenTreeLclVarCommon* lcl, ASSERT_VALARG_TP
         Limit      limit(Limit::keUndef);
         genTreeOps cmpOper = GT_NONE;
 
+        LclSsaVarDsc* ssaData     = m_pCompiler->lvaTable[lcl->gtLclNum].GetPerSsaData(lcl->gtSsaNum);
+        ValueNum      normalLclVN = m_pCompiler->vnStore->VNNormalValue(ssaData->m_vnPair, VNK_Conservative);
+
         // Current assertion is of the form (i < len - cns) != 0
         if (curAssertion->IsCheckedBoundArithBound())
         {
@@ -548,8 +551,8 @@ void RangeCheck::MergeEdgeAssertions(GenTreeLclVarCommon* lcl, ASSERT_VALARG_TP
             // Get i, len, cns and < as "info."
             m_pCompiler->vnStore->GetCompareCheckedBoundArithInfo(curAssertion->op1.vn, &info);
 
-            if (m_pCompiler->lvaTable[lcl->gtLclNum].GetPerSsaData(lcl->gtSsaNum)->m_vnPair.GetConservative() !=
-                info.cmpOp)
+            // If we don't have the same variable we are comparing against, bail.
+            if (normalLclVN != info.cmpOp)
             {
                 continue;
             }
@@ -577,13 +580,12 @@ void RangeCheck::MergeEdgeAssertions(GenTreeLclVarCommon* lcl, ASSERT_VALARG_TP
             // Get the info as "i", "<" and "len"
             m_pCompiler->vnStore->GetCompareCheckedBound(curAssertion->op1.vn, &info);
 
-            ValueNum lclVn =
-                m_pCompiler->lvaTable[lcl->gtLclNum].GetPerSsaData(lcl->gtSsaNum)->m_vnPair.GetConservative();
             // If we don't have the same variable we are comparing against, bail.
-            if (lclVn != info.cmpOp)
+            if (normalLclVN != info.cmpOp)
             {
                 continue;
             }
+
             limit   = Limit(Limit::keBinOpArray, info.vnBound, 0);
             cmpOper = (genTreeOps)info.cmpOper;
         }
@@ -595,11 +597,8 @@ void RangeCheck::MergeEdgeAssertions(GenTreeLclVarCommon* lcl, ASSERT_VALARG_TP
             // Get the info as "i", "<" and "100"
             m_pCompiler->vnStore->GetConstantBoundInfo(curAssertion->op1.vn, &info);
 
-            ValueNum lclVn =
-                m_pCompiler->lvaTable[lcl->gtLclNum].GetPerSsaData(lcl->gtSsaNum)->m_vnPair.GetConservative();
-
             // If we don't have the same variable we are comparing against, bail.
-            if (lclVn != info.cmpOpVN)
+            if (normalLclVN != info.cmpOpVN)
             {
                 continue;
             }
@@ -627,7 +626,7 @@ void RangeCheck::MergeEdgeAssertions(GenTreeLclVarCommon* lcl, ASSERT_VALARG_TP
         }
 #endif
 
-        ValueNum arrLenVN = m_pCurBndsChk->gtArrLen->gtVNPair.GetConservative();
+        ValueNum arrLenVN = m_pCompiler->vnStore->VNNormalValue(m_pCurBndsChk->gtArrLen->gtVNPair, VNK_Conservative);
 
         if (m_pCompiler->vnStore->IsVNConstant(arrLenVN))
         {
@@ -745,7 +744,7 @@ void RangeCheck::MergeEdgeAssertions(GenTreeLclVarCommon* lcl, ASSERT_VALARG_TP
 void RangeCheck::MergeAssertion(BasicBlock* block, GenTree* op, Range* pRange DEBUGARG(int indent))
 {
     JITDUMP("Merging assertions from pred edges of " FMT_BB " for op [%06d] " FMT_VN "\n", block->bbNum,
-            Compiler::dspTreeID(op), op->gtVNPair.GetConservative());
+            Compiler::dspTreeID(op), m_pCompiler->vnStore->VNNormalValue(op->gtVNPair, VNK_Conservative));
     ASSERT_TP assertions = BitVecOps::UninitVal();
 
     // If we have a phi arg, we can get to the block from it and use its assertion out.
@@ -1060,7 +1059,7 @@ Range RangeCheck::ComputeRange(BasicBlock* block, GenTree* expr, bool monotonic
     bool  newlyAdded = !m_pSearchPath->Set(expr, block);
     Range range      = Limit(Limit::keUndef);
 
-    ValueNum vn = expr->gtVNPair.GetConservative();
+    ValueNum vn = m_pCompiler->vnStore->VNNormalValue(expr->gtVNPair, VNK_Conservative);
     // If newly added in the current search path, then reduce the budget.
     if (newlyAdded)
     {
index bdb13eb..8b6d9c5 100644 (file)
@@ -639,7 +639,7 @@ T ValueNumStore::EvalOpSpecialized(VNFunc vnf, T v0)
 //
 
 template <typename T>
-T ValueNumStore::EvalOp(VNFunc vnf, T v0, T v1, ValueNum* pExcSet)
+T ValueNumStore::EvalOp(VNFunc vnf, T v0, T v1)
 {
     // Here we handle the binary ops that are the same for all types.
 
@@ -2707,7 +2707,6 @@ ValueNum ValueNumStore::EvalFuncForConstantArgs(var_types typ, VNFunc func, Valu
     }
 
     ValueNum result; // left uninitialized, we are required to initialize it on all paths below.
-    ValueNum excSet = VNForEmptyExcSet();
 
     // Are both args of the same type?
     if (arg0VNtyp == arg1VNtyp)
@@ -2725,17 +2724,16 @@ ValueNum ValueNumStore::EvalFuncForConstantArgs(var_types typ, VNFunc func, Valu
             else
             {
                 assert(typ == TYP_INT);
-                int resultVal = EvalOp<int>(func, arg0Val, arg1Val, &excSet);
+                int resultVal = EvalOp<int>(func, arg0Val, arg1Val);
                 // Bin op on a handle results in a handle.
                 ValueNum handleVN = IsVNHandle(arg0VN) ? arg0VN : IsVNHandle(arg1VN) ? arg1VN : NoVN;
                 if (handleVN != NoVN)
                 {
-                    assert(excSet == VNForEmptyExcSet()); // Handles aren't allowed to generate exceptions
                     result = VNForHandle(ssize_t(resultVal), GetHandleFlags(handleVN)); // Use VN for Handle
                 }
                 else
                 {
-                    result = VNWithExc(VNForIntCon(resultVal), excSet);
+                    result = VNForIntCon(resultVal);
                 }
             }
         }
@@ -2752,12 +2750,17 @@ ValueNum ValueNumStore::EvalFuncForConstantArgs(var_types typ, VNFunc func, Valu
             else
             {
                 assert(typ == TYP_LONG);
-                INT64    resultVal = EvalOp<INT64>(func, arg0Val, arg1Val, &excSet);
+                INT64    resultVal = EvalOp<INT64>(func, arg0Val, arg1Val);
                 ValueNum handleVN  = IsVNHandle(arg0VN) ? arg0VN : IsVNHandle(arg1VN) ? arg1VN : NoVN;
-                ValueNum resultVN  = (handleVN != NoVN)
-                                        ? VNForHandle(ssize_t(resultVal), GetHandleFlags(handleVN)) // Use VN for Handle
-                                        : VNForLongCon(resultVal);
-                result = VNWithExc(resultVN, excSet);
+
+                if (handleVN != NoVN)
+                {
+                    result = VNForHandle(ssize_t(resultVal), GetHandleFlags(handleVN)); // Use VN for Handle
+                }
+                else
+                {
+                    result = VNForLongCon(resultVal);
+                }
             }
         }
         else // both args are TYP_REF or both args are TYP_BYREF
@@ -2772,14 +2775,14 @@ ValueNum ValueNumStore::EvalFuncForConstantArgs(var_types typ, VNFunc func, Valu
             }
             else if (typ == TYP_INT) // We could see GT_OR of a constant ByRef and Null
             {
-                int resultVal = (int)EvalOp<INT64>(func, arg0Val, arg1Val, &excSet);
-                result        = VNWithExc(VNForIntCon(resultVal), excSet);
+                int resultVal = (int)EvalOp<INT64>(func, arg0Val, arg1Val);
+                result        = VNForIntCon(resultVal);
             }
             else // We could see GT_OR of a constant ByRef and Null
             {
                 assert((typ == TYP_BYREF) || (typ == TYP_LONG));
-                INT64 resultVal = EvalOp<INT64>(func, arg0Val, arg1Val, &excSet);
-                result          = VNWithExc(VNForByrefCon(resultVal), excSet);
+                INT64 resultVal = EvalOp<INT64>(func, arg0Val, arg1Val);
+                result          = VNForByrefCon(resultVal);
             }
         }
     }
@@ -2798,37 +2801,28 @@ ValueNum ValueNumStore::EvalFuncForConstantArgs(var_types typ, VNFunc func, Valu
         }
         else if (typ == TYP_INT) // We could see GT_OR of an int and constant ByRef or Null
         {
-            int resultVal = (int)EvalOp<INT64>(func, arg0Val, arg1Val, &excSet);
-            result        = VNWithExc(VNForIntCon(resultVal), excSet);
+            int resultVal = (int)EvalOp<INT64>(func, arg0Val, arg1Val);
+            result        = VNForIntCon(resultVal);
         }
         else
         {
             assert(typ != TYP_INT);
-            ValueNum resultValx = VNForEmptyExcSet();
-            INT64    resultVal  = EvalOp<INT64>(func, arg0Val, arg1Val, &resultValx);
+            INT64 resultVal = EvalOp<INT64>(func, arg0Val, arg1Val);
 
-            // check for the Exception case
-            if (resultValx != VNForEmptyExcSet())
-            {
-                result = VNWithExc(VNForVoid(), resultValx);
-            }
-            else
+            switch (typ)
             {
-                switch (typ)
-                {
-                    case TYP_BYREF:
-                        result = VNForByrefCon(resultVal);
-                        break;
-                    case TYP_LONG:
-                        result = VNForLongCon(resultVal);
-                        break;
-                    case TYP_REF:
-                        assert(resultVal == 0); // Only valid REF constant
-                        result = VNForNull();
-                        break;
-                    default:
-                        unreached();
-                }
+                case TYP_BYREF:
+                    result = VNForByrefCon(resultVal);
+                    break;
+                case TYP_LONG:
+                    result = VNForLongCon(resultVal);
+                    break;
+                case TYP_REF:
+                    assert(resultVal == 0); // Only valid REF constant
+                    result = VNForNull();
+                    break;
+                default:
+                    unreached();
             }
         }
     }
@@ -2876,23 +2870,17 @@ ValueNum ValueNumStore::EvalFuncForConstantFPArgs(var_types typ, VNFunc func, Va
         assert(varTypeIsFloating(typ));
         assert(arg0VNtyp == typ);
 
-        ValueNum exception = VNForEmptyExcSet();
-
         if (typ == TYP_FLOAT)
         {
-            float floatResultVal =
-                EvalOp<float>(func, GetConstantSingle(arg0VN), GetConstantSingle(arg1VN), &exception);
-            assert(exception == VNForEmptyExcSet()); // Floating point ops don't throw.
-            result = VNForFloatCon(floatResultVal);
+            float floatResultVal = EvalOp<float>(func, GetConstantSingle(arg0VN), GetConstantSingle(arg1VN));
+            result               = VNForFloatCon(floatResultVal);
         }
         else
         {
             assert(typ == TYP_DOUBLE);
 
-            double doubleResultVal =
-                EvalOp<double>(func, GetConstantDouble(arg0VN), GetConstantDouble(arg1VN), &exception);
-            assert(exception == VNForEmptyExcSet()); // Floating point ops don't throw.
-            result = VNForDoubleCon(doubleResultVal);
+            double doubleResultVal = EvalOp<double>(func, GetConstantDouble(arg0VN), GetConstantDouble(arg1VN));
+            result                 = VNForDoubleCon(doubleResultVal);
         }
     }
 
@@ -8058,7 +8046,7 @@ ValueNumPair ValueNumStore::VNPairForCast(ValueNumPair srcVNPair,
     ValueNumPair castArgxVNP = ValueNumStore::VNPForEmptyExcSet();
     VNPUnpackExc(srcVNPair, &castArgVNP, &castArgxVNP);
 
-    // When we're considering actual value returned by a non-checking cast (or a checking cast that succeeds),
+    // When we're considering actual value returned by a non-checking cast, (hasOverflowCheck is false)
     // whether or not the source is unsigned does *not* matter for non-widening casts.
     // That is, if we cast an int or a uint to short, we just extract the first two bytes from the source
     // bit pattern, not worrying about the interpretation.  The same is true in casting between signed/unsigned
@@ -8068,26 +8056,25 @@ ValueNumPair ValueNumStore::VNPairForCast(ValueNumPair srcVNPair,
     // Important: Casts to floating point cannot be optimized in this fashion. (bug 946768)
     //
     bool srcIsUnsignedNorm = srcIsUnsigned;
-    if (genTypeSize(castToType) <= genTypeSize(castFromType) && !varTypeIsFloating(castToType))
+    if (!hasOverflowCheck && !varTypeIsFloating(castToType) && (genTypeSize(castToType) <= genTypeSize(castFromType)))
     {
         srcIsUnsignedNorm = false;
     }
 
+    VNFunc       vnFunc     = hasOverflowCheck ? VNF_CastOvf : VNF_Cast;
     ValueNum     castTypeVN = VNForCastOper(castToType, srcIsUnsignedNorm);
     ValueNumPair castTypeVNPair(castTypeVN, castTypeVN);
-    ValueNumPair castNormRes = VNPairForFunc(resultType, VNF_Cast, castArgVNP, castTypeVNPair);
+    ValueNumPair castNormRes = VNPairForFunc(resultType, vnFunc, castArgVNP, castTypeVNPair);
 
     ValueNumPair resultVNP = VNPWithExc(castNormRes, castArgxVNP);
 
     // If we have a check for overflow, add the exception information.
     if (hasOverflowCheck)
     {
-        // For overflow checking, we always need to know whether the source is unsigned.
-        castTypeVNPair.SetBoth(VNForCastOper(castToType, srcIsUnsigned));
-        ValueNumPair excSet =
-            VNPExcSetSingleton(VNPairForFunc(TYP_REF, VNF_ConvOverflowExc, castArgVNP, castTypeVNPair));
-        excSet    = VNPExcSetUnion(excSet, castArgxVNP);
-        resultVNP = VNPWithExc(castNormRes, excSet);
+        ValueNumPair ovfChk = VNPairForFunc(TYP_REF, VNF_ConvOverflowExc, castArgVNP, castTypeVNPair);
+        ValueNumPair excSet = VNPExcSetSingleton(ovfChk);
+        excSet              = VNPExcSetUnion(excSet, castArgxVNP);
+        resultVNP           = VNPWithExc(castNormRes, excSet);
     }
 
     return resultVNP;
index aefec01..b66f0d2 100644 (file)
@@ -197,13 +197,12 @@ private:
     // returns vnf(v0)  for int/INT32
     int EvalOpInt(VNFunc vnf, int v0);
 
-    // If vnf(v0, v1) would raise an exception, sets *pExcSet to the singleton set containing the exception, and
-    // returns (T)0. Otherwise, returns vnf(v0, v1).
+    // returns vnf(v0, v1).
     template <typename T>
-    T EvalOp(VNFunc vnf, T v0, T v1, ValueNum* pExcSet);
+    T EvalOp(VNFunc vnf, T v0, T v1);
 
     // returns vnf(v0, v1)  for int/INT32
-    int EvalOpInt(VNFunc vnf, int v0, int v1, ValueNum* pExcSet);
+    int EvalOpInt(VNFunc vnf, int v0, int v1);
 
     // return vnf(v0) or vnf(v0, v1), respectively (must, of course be unary/binary ops, respectively.)
     template <typename T>