summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrian Sullivan <briansul@microsoft.com>2018-12-10 17:24:10 -0800
committerGitHub <noreply@github.com>2018-12-10 17:24:10 -0800
commit335804f565c0bb18792b7097b3a1258f6cf5224a (patch)
tree1877505f00393db80a69565627507e7792a600fe
parent86ae71ac96ed44399de26bad3542fc5ddc04bbf9 (diff)
parent842f575fac8d64467bb4a15ef9fe893bedc536ad (diff)
downloadcoreclr-335804f565c0bb18792b7097b3a1258f6cf5224a.tar.gz
coreclr-335804f565c0bb18792b7097b3a1258f6cf5224a.tar.bz2
coreclr-335804f565c0bb18792b7097b3a1258f6cf5224a.zip
Merge pull request #21386 from briansull/issue_19925
Preserve the exception sets from child nodes when we create a new unique value number
-rw-r--r--src/jit/compiler.h4
-rw-r--r--src/jit/valuenum.cpp233
-rw-r--r--src/jit/valuenum.h14
3 files changed, 210 insertions, 41 deletions
diff --git a/src/jit/compiler.h b/src/jit/compiler.h
index ae23da1733..082dfa0d52 100644
--- a/src/jit/compiler.h
+++ b/src/jit/compiler.h
@@ -4470,8 +4470,8 @@ public:
// Returns the corresponding VNFunc to use for value numbering
VNFunc fgValueNumberJitHelperMethodVNFunc(CorInfoHelpFunc helpFunc);
- // Adds the exception set for the current tree node which is performing a memory indirection operation
- void fgValueNumberAddExceptionSetForIndirection(GenTree* tree);
+ // Adds the exception set for the current tree node which has a memory indirection operation
+ void fgValueNumberAddExceptionSetForIndirection(GenTree* tree, GenTree* baseAddr);
// Adds the exception sets for the current tree node which is performing a division or modulus operation
void fgValueNumberAddExceptionSetForDivision(GenTree* tree);
diff --git a/src/jit/valuenum.cpp b/src/jit/valuenum.cpp
index 58a2a70d27..852cd65d55 100644
--- a/src/jit/valuenum.cpp
+++ b/src/jit/valuenum.cpp
@@ -1125,7 +1125,7 @@ ValueNum ValueNumStore::VNExcSetUnion(ValueNum xs0, ValueNum xs1)
// (see VNExcSetUnion for more details)
//
// Notes: - This method is used to form a Value Number Pair when we
-// want both the Liberal and Conservative Value NUmbers
+// want both the Liberal and Conservative Value Numbers
//
ValueNumPair ValueNumStore::VNPExcSetUnion(ValueNumPair xs0vnp, ValueNumPair xs1vnp)
{
@@ -1195,7 +1195,7 @@ ValueNum ValueNumStore::VNExcSetIntersection(ValueNum xs0, ValueNum xs1)
// (see VNExcSetIntersection for more details)
//
// Notes: - This method is used to form a Value Number Pair when we
-// want both the Liberal and Conservative Value NUmbers
+// want both the Liberal and Conservative Value Numbers
//
ValueNumPair ValueNumStore::VNPExcSetIntersection(ValueNumPair xs0vnp, ValueNumPair xs1vnp)
{
@@ -1302,7 +1302,7 @@ bool ValueNumStore::VNExcIsSubset(ValueNum vnFullSet, ValueNum vnCandidateSet)
// the normal and the exception set components.
//
// Arguments:
-// vnWx - The value number of the first exception set
+// vnWx - A value number, it may have an exception set
// pvn - a write back pointer to the normal value portion of 'vnWx'
// pvnx - a write back pointer for the exception set portion of 'vnWx'
//
@@ -1337,7 +1337,7 @@ void ValueNumStore::VNUnpackExc(ValueNum vnWx, ValueNum* pvn, ValueNum* pvnx)
// (see VNUnpackExc for more details)
//
// Notes: - This method is used to form a Value Number Pair when we
-// want both the Liberal and Conservative Value NUmbers
+// want both the Liberal and Conservative Value Numbers
//
void ValueNumStore::VNPUnpackExc(ValueNumPair vnpWx, ValueNumPair* pvnp, ValueNumPair* pvnpx)
{
@@ -1345,6 +1345,44 @@ void ValueNumStore::VNPUnpackExc(ValueNumPair vnpWx, ValueNumPair* pvnp, ValueNu
VNUnpackExc(vnpWx.GetConservative(), pvnp->GetConservativeAddr(), pvnpx->GetConservativeAddr());
}
+//-------------------------------------------------------------------------------------
+// VNUnionExcSet: - Given a ValueNum 'vnWx' and a current 'vnExcSet', return an
+// exception set of the Union of both exception sets.
+//
+// Arguments:
+// vnWx - A value number, it may have an exception set
+// vnExcSet - The value number for the current exception set
+//
+// Return Values: - The value number of the Union of the exception set of 'vnWx'
+// with the current 'vnExcSet'.
+//
+// Note: When 'vnWx' does not have an exception set, 'vnExcSet' is returned.
+//
+ValueNum ValueNumStore::VNUnionExcSet(ValueNum vnWx, ValueNum vnExcSet)
+{
+ assert(vnWx != NoVN);
+ VNFuncApp funcApp;
+ if (GetVNFunc(vnWx, &funcApp) && funcApp.m_func == VNF_ValWithExc)
+ {
+ vnExcSet = VNExcSetUnion(funcApp.m_args[1], vnExcSet);
+ }
+ return vnExcSet;
+}
+
+//-------------------------------------------------------------------------------------
+// VNPUnionExcSet: - Given a ValueNum 'vnWx' and a current 'excSet', return an
+// exception set of the Union of both exception sets.
+// (see VNUnionExcSet for more details)
+//
+// Notes: - This method is used to form a Value Number Pair when we
+// want both the Liberal and Conservative Value Numbers
+//
+ValueNumPair ValueNumStore::VNPUnionExcSet(ValueNumPair vnpWx, ValueNumPair vnpExcSet)
+{
+ return ValueNumPair(VNUnionExcSet(vnpWx.GetLiberal(), vnpExcSet.GetLiberal()),
+ VNUnionExcSet(vnpWx.GetConservative(), vnpExcSet.GetConservative()));
+}
+
//--------------------------------------------------------------------------------
// VNNormalValue: - Returns a Value Number that represents the result for the
// normal (non-exceptional) evaluation for the expression.
@@ -1375,6 +1413,47 @@ ValueNum ValueNumStore::VNNormalValue(ValueNum vn)
}
}
+//------------------------------------------------------------------------------------
+// VNMakeNormalUnique:
+//
+// Arguments:
+// vn - The current Value Number for the expression, including any excSet.
+// This excSet is an optional item and represents the set of
+// possible exceptions for the expression.
+//
+// Return Value:
+// - The normal value is set to a new unique VN, while keeping
+// the excSet (if any)
+//
+ValueNum ValueNumStore::VNMakeNormalUnique(ValueNum orig)
+{
+ // First Unpack the existing Norm,Exc for 'elem'
+ ValueNum vnOrigNorm;
+ ValueNum vnOrigExcSet;
+ VNUnpackExc(orig, &vnOrigNorm, &vnOrigExcSet);
+
+ // Replace the normal value with a unique ValueNum
+ ValueNum vnUnique = VNForExpr(m_pComp->compCurBB, TypeOfVN(vnOrigNorm));
+
+ // Keep any ExcSet from 'elem'
+ return VNWithExc(vnUnique, vnOrigExcSet);
+}
+
+//--------------------------------------------------------------------------------
+// VNPMakeNormalUniquePair:
+//
+// Arguments:
+// vnp - The Value Number Pair for the expression, including any excSet.
+//
+// Return Value:
+// - The normal values are set to a new unique VNs, while keeping
+// the excSets (if any)
+//
+ValueNumPair ValueNumStore::VNPMakeNormalUniquePair(ValueNumPair vnp)
+{
+ return ValueNumPair(VNMakeNormalUnique(vnp.GetLiberal()), VNMakeNormalUnique(vnp.GetConservative()));
+}
+
//--------------------------------------------------------------------------------
// VNNormalValue: - Returns a Value Number that represents the result for the
// normal (non-exceptional) evaluation for the expression.
@@ -1406,7 +1485,7 @@ ValueNum ValueNumStore::VNNormalValue(ValueNumPair vnp, ValueNumKind vnk)
// vnp - The Value Number Pair for the expression, including any excSet.
//
// Notes: - This method is used to form a Value Number Pair using both
-// the Liberal and Conservative Value NUmbers normal (non-exceptional)
+// the Liberal and Conservative Value Numbers normal (non-exceptional)
//
ValueNumPair ValueNumStore::VNPNormalPair(ValueNumPair vnp)
{
@@ -1450,7 +1529,7 @@ ValueNum ValueNumStore::VNExceptionSet(ValueNum vn)
// (see VNExceptionSet for more details)
//
// Notes: - This method is used to form a Value Number Pair when we
-// want both the Liberal and Conservative Value NUmbers
+// want both the Liberal and Conservative Value Numbers
//
ValueNumPair ValueNumStore::VNPExceptionSet(ValueNumPair vnp)
{
@@ -1496,7 +1575,7 @@ ValueNum ValueNumStore::VNWithExc(ValueNum vn, ValueNum excSet)
// (see VNWithExc for more details)
//
// Notes: = This method is used to form a Value Number Pair when we
-// want both the Liberal and Conservative Value NUmbers
+// want both the Liberal and Conservative Value Numbers
//
ValueNumPair ValueNumStore::VNPWithExc(ValueNumPair vnp, ValueNumPair excSetVNP)
{
@@ -3651,15 +3730,15 @@ ValueNum ValueNumStore::VNApplySelectorsTypeCheck(ValueNum elem, var_types indTy
// Reading beyong the end of 'elem'
// return a new unique value number
- elem = VNForExpr(nullptr, indType);
+ elem = VNMakeNormalUnique(elem);
+
JITDUMP(" *** Mismatched types in VNApplySelectorsTypeCheck (reading beyond the end)\n");
}
else if (varTypeIsStruct(indType))
{
- // indType is TYP_STRUCT
-
// return a new unique value number
- elem = VNForExpr(nullptr, indType);
+ elem = VNMakeNormalUnique(elem);
+
JITDUMP(" *** Mismatched types in VNApplySelectorsTypeCheck (indType is TYP_STRUCT)\n");
}
else
@@ -3670,6 +3749,7 @@ ValueNum ValueNumStore::VNApplySelectorsTypeCheck(ValueNum elem, var_types indTy
elem = VNForCast(elem, indType, elemTyp);
}
}
+
return elem;
}
@@ -3693,7 +3773,8 @@ ValueNum ValueNumStore::VNApplySelectorsAssignTypeCoerce(ValueNum elem, var_type
if (varTypeIsStruct(indType))
{
// return a new unique value number
- elem = VNForExpr(block, indType);
+ elem = VNMakeNormalUnique(elem);
+
JITDUMP(" *** Mismatched types in VNApplySelectorsAssignTypeCoerce (indType is TYP_STRUCT)\n");
}
else
@@ -3702,6 +3783,9 @@ ValueNum ValueNumStore::VNApplySelectorsAssignTypeCoerce(ValueNum elem, var_type
// insert a cast of elem to 'indType'
elem = VNForCast(elem, indType, elemTyp);
+
+ JITDUMP(" Cast to %s inserted in VNApplySelectorsAssignTypeCoerce (elemTyp is %s)\n",
+ varTypeName(indType), varTypeName(elemTyp));
}
}
}
@@ -4155,6 +4239,7 @@ ValueNum Compiler::fgValueNumberArrIndexVal(GenTree* tree,
if (tree != nullptr)
{
tree->gtVNPair.SetLiberal(selectedElem);
+
// TODO-CQ: what to do here about exceptions? We don't have the array and ind conservative
// values, so we don't have their exceptions. Maybe we should.
tree->gtVNPair.SetConservative(vnStore->VNForExpr(compCurBB, tree->TypeGet()));
@@ -6133,7 +6218,7 @@ ValueNum Compiler::fgMemoryVNForLoopSideEffects(MemoryKind memoryKind,
#ifdef DEBUG
if (verbose)
{
- printf(" Loop %d has memory havoc effect; heap state is new fresh $%x.\n", loopNum, res);
+ printf(" Loop %d has memory havoc effect; heap state is new unique $%x.\n", loopNum, res);
}
#endif // DEBUG
return res;
@@ -6664,7 +6749,7 @@ void Compiler::fgValueNumberBlockAssignment(GenTree* tree)
else
{
JITDUMP(" *** Missing field sequence info for Src/RHS of COPYBLK\n");
- rhsVNPair.SetBoth(vnStore->VNForExpr(compCurBB, indType)); // a new unique value number
+ isNewUniq = true;
}
}
else if (srcAddrFuncApp.m_func == VNF_PtrToArrElem)
@@ -8151,13 +8236,36 @@ void Compiler::fgValueNumberTree(GenTree* tree)
break;
case GT_LOCKADD: // Binop
- case GT_XADD: // Binop
- case GT_XCHG: // Binop
- assert(!tree->OperIs(GT_LOCKADD) && "LOCKADD should not appear before lowering");
- // For CMPXCHG and other intrinsics add an arbitrary side effect on GcHeap/ByrefExposed.
+ noway_assert("LOCKADD should not appear before lowering");
+ break;
+
+ case GT_XADD: // Binop
+ case GT_XCHG: // Binop
+ {
+ // For XADD and XCHG other intrinsics add an arbitrary side effect on GcHeap/ByrefExposed.
fgMutateGcHeap(tree DEBUGARG("Interlocked intrinsic"));
- tree->gtVNPair.SetBoth(vnStore->VNForExpr(compCurBB, tree->TypeGet()));
+
+ assert(tree->OperIsImplicitIndir()); // special node with an implicit indirections
+
+ GenTree* addr = tree->gtOp.gtOp1; // op1
+ GenTree* data = tree->gtOp.gtOp2; // op2
+
+ ValueNumPair vnpExcSet = ValueNumStore::VNPForEmptyExcSet();
+
+ vnpExcSet = vnStore->VNPUnionExcSet(data->gtVNPair, vnpExcSet);
+ vnpExcSet = vnStore->VNPUnionExcSet(addr->gtVNPair, vnpExcSet);
+
+ // The normal value is a new unique VN.
+ ValueNumPair normalPair;
+ normalPair.SetBoth(vnStore->VNForExpr(compCurBB, tree->TypeGet()));
+
+ // Attach the combined exception set
+ tree->gtVNPair = vnStore->VNPWithExc(normalPair, vnpExcSet);
+
+ // add the null check exception for 'addr' to the tree's value number
+ fgValueNumberAddExceptionSetForIndirection(tree, addr);
break;
+ }
case GT_JTRUE:
case GT_LIST:
@@ -8202,17 +8310,20 @@ void Compiler::fgValueNumberTree(GenTree* tree)
case GT_HW_INTRINSIC_CHK:
#endif // FEATURE_HW_INTRINSICS
{
- // A bounds check node has no value, but may throw exceptions.
- ValueNumPair excSet = vnStore->VNPExcSetSingleton(
- vnStore->VNPairForFunc(TYP_REF, VNF_IndexOutOfRangeExc,
- vnStore->VNPNormalPair(tree->AsBoundsChk()->gtIndex->gtVNPair),
- vnStore->VNPNormalPair(tree->AsBoundsChk()->gtArrLen->gtVNPair)));
- excSet =
- vnStore->VNPExcSetUnion(excSet, vnStore->VNPExceptionSet(tree->AsBoundsChk()->gtIndex->gtVNPair));
- excSet =
- vnStore->VNPExcSetUnion(excSet, vnStore->VNPExceptionSet(tree->AsBoundsChk()->gtArrLen->gtVNPair));
+ ValueNumPair vnpIndex = tree->AsBoundsChk()->gtIndex->gtVNPair;
+ ValueNumPair vnpArrLen = tree->AsBoundsChk()->gtArrLen->gtVNPair;
+
+ // Construct the exception set for bounds check
+ ValueNumPair vnpExcSet = vnStore->VNPExcSetSingleton(
+ vnStore->VNPairForFunc(TYP_REF, VNF_IndexOutOfRangeExc, vnStore->VNPNormalPair(vnpIndex),
+ vnStore->VNPNormalPair(vnpArrLen)));
- tree->gtVNPair = vnStore->VNPWithExc(vnStore->VNPForVoid(), excSet);
+ // And collect the exceptions from Index and ArrLen
+ vnpExcSet = vnStore->VNPUnionExcSet(vnpIndex, vnpExcSet);
+ vnpExcSet = vnStore->VNPUnionExcSet(vnpArrLen, vnpExcSet);
+
+ // A bounds check node has no value, but may throw exceptions.
+ tree->gtVNPair = vnStore->VNPWithExc(vnStore->VNPForVoid(), vnpExcSet);
// Record non-constant value numbers that are used as the length argument to bounds checks, so that
// assertion prop will know that comparisons against them are worth analyzing.
@@ -8225,10 +8336,38 @@ void Compiler::fgValueNumberTree(GenTree* tree)
break;
case GT_CMPXCHG: // Specialop
+ {
// For CMPXCHG and other intrinsics add an arbitrary side effect on GcHeap/ByrefExposed.
fgMutateGcHeap(tree DEBUGARG("Interlocked intrinsic"));
- tree->gtVNPair.SetBoth(vnStore->VNForExpr(compCurBB, tree->TypeGet()));
+
+ GenTreeCmpXchg* const cmpXchg = tree->AsCmpXchg();
+
+ assert(tree->OperIsImplicitIndir()); // special node with an implicit indirections
+
+ GenTree* location = cmpXchg->gtOpLocation; // arg1
+ GenTree* value = cmpXchg->gtOpValue; // arg2
+ GenTree* comparand = cmpXchg->gtOpComparand; // arg3
+
+ ValueNumPair vnpExcSet = ValueNumStore::VNPForEmptyExcSet();
+
+ // Collect the exception sets from our operands
+ vnpExcSet = vnStore->VNPUnionExcSet(location->gtVNPair, vnpExcSet);
+ vnpExcSet = vnStore->VNPUnionExcSet(value->gtVNPair, vnpExcSet);
+ vnpExcSet = vnStore->VNPUnionExcSet(comparand->gtVNPair, vnpExcSet);
+
+ // The normal value is a new unique VN.
+ ValueNumPair normalPair;
+ normalPair.SetBoth(vnStore->VNForExpr(compCurBB, tree->TypeGet()));
+
+ // Attach the combined exception set
+ tree->gtVNPair = vnStore->VNPWithExc(normalPair, vnpExcSet);
+
+ // add the null check exception for 'location' to the tree's value number
+ fgValueNumberAddExceptionSetForIndirection(tree, location);
+ // add the null check exception for 'comparand' to the tree's value number
+ fgValueNumberAddExceptionSetForIndirection(tree, comparand);
break;
+ }
default:
tree->gtVNPair.SetBoth(vnStore->VNForExpr(compCurBB, tree->TypeGet()));
@@ -9060,6 +9199,8 @@ bool Compiler::fgValueNumberHelperCall(GenTreeCall* call)
// Arguments:
// tree - The current GenTree node,
// It must be some kind of an indirection node
+// or have an implicit indirection
+// baseAddr - The address that we are indirecting
//
// Return Value:
// - The tree's gtVNPair is updated to include the VNF_nullPtrExc
@@ -9072,11 +9213,10 @@ bool Compiler::fgValueNumberHelperCall(GenTreeCall* call)
// For arrays the base address currently includes the
// index calculations.
//
-void Compiler::fgValueNumberAddExceptionSetForIndirection(GenTree* tree)
+void Compiler::fgValueNumberAddExceptionSetForIndirection(GenTree* tree, GenTree* baseAddr)
{
- // We should have an Unary operator
- assert(tree->OperIsUnary());
- GenTree* baseAddr = tree->gtGetOp1();
+ // We should have tree that a unary indirection or a tree node with an implicit indirection
+ assert(tree->OperIsUnary() || tree->OperIsImplicitIndir());
// We evaluate the baseAddr ValueNumber further in order
// to obtain a better value to use for the null check exeception.
@@ -9483,14 +9623,29 @@ void Compiler::fgValueNumberAddExceptionSet(GenTree* tree)
// Don't add exception set on LHS of assignment
break;
}
- // fall through
+ __fallthrough;
- case GT_BLK: // All Block opcodes contain at least one indirection
+ case GT_BLK:
case GT_OBJ:
case GT_DYN_BLK:
- case GT_ARR_LENGTH: // Implicit null check.
- case GT_NULLCHECK: // Explicit null check.
- fgValueNumberAddExceptionSetForIndirection(tree);
+ case GT_NULLCHECK:
+ fgValueNumberAddExceptionSetForIndirection(tree, tree->AsIndir()->Addr());
+ break;
+
+ case GT_ARR_LENGTH:
+ fgValueNumberAddExceptionSetForIndirection(tree, tree->AsArrLen()->ArrRef());
+ break;
+
+ case GT_ARR_ELEM:
+ fgValueNumberAddExceptionSetForIndirection(tree, tree->gtArrElem.gtArrObj);
+ break;
+
+ case GT_ARR_INDEX:
+ fgValueNumberAddExceptionSetForIndirection(tree, tree->gtArrIndex.ArrObj());
+ break;
+
+ case GT_ARR_OFFSET:
+ fgValueNumberAddExceptionSetForIndirection(tree, tree->gtArrOffs.gtArrObj);
break;
case GT_DIV:
diff --git a/src/jit/valuenum.h b/src/jit/valuenum.h
index dd0a18c724..a22b905c2b 100644
--- a/src/jit/valuenum.h
+++ b/src/jit/valuenum.h
@@ -403,6 +403,20 @@ public:
void VNPUnpackExc(ValueNumPair vnWx, ValueNumPair* pvn, ValueNumPair* pvnx);
+ // This returns the Union of exceptions from vnWx and vnExcSet
+ ValueNum VNUnionExcSet(ValueNum vnWx, ValueNum vnExcSet);
+
+ // This returns the Union of exceptions from vnpWx and vnpExcSet
+ ValueNumPair VNPUnionExcSet(ValueNumPair vnpWx, ValueNumPair vnpExcSet);
+
+ // Sets the normal value to a new unique ValueNum
+ // Keeps any Exception set values
+ ValueNum VNMakeNormalUnique(ValueNum vn);
+
+ // Sets the liberal & conservative
+ // Keeps any Exception set values
+ ValueNumPair VNPMakeNormalUniquePair(ValueNumPair vnp);
+
// If "vn" is a "VNF_ValWithExc(norm, excSet)" value, returns the "norm" argument; otherwise,
// just returns "vn".
// The Normal value is the value number of the expression when no exceptions occurred