diff options
author | Brian Sullivan <briansul@microsoft.com> | 2018-12-10 17:24:10 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-12-10 17:24:10 -0800 |
commit | 335804f565c0bb18792b7097b3a1258f6cf5224a (patch) | |
tree | 1877505f00393db80a69565627507e7792a600fe | |
parent | 86ae71ac96ed44399de26bad3542fc5ddc04bbf9 (diff) | |
parent | 842f575fac8d64467bb4a15ef9fe893bedc536ad (diff) | |
download | coreclr-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.h | 4 | ||||
-rw-r--r-- | src/jit/valuenum.cpp | 233 | ||||
-rw-r--r-- | src/jit/valuenum.h | 14 |
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 |