From 4204c275f595746e44cd668d65ee5c50f935c716 Mon Sep 17 00:00:00 2001 From: SingleAccretion Date: Thu, 6 Jan 2022 23:53:20 +0300 Subject: [PATCH 01/30] Add a simple exception sets checker --- src/coreclr/jit/compiler.h | 4 ++++ src/coreclr/jit/valuenum.cpp | 46 ++++++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+) diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index 5a16ac8a58bf8..61b8e4788208d 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -5560,6 +5560,10 @@ class Compiler // Adds the exception sets for the current tree node void fgValueNumberAddExceptionSet(GenTree* tree); +#ifdef DEBUG + void fgDebugCheckExceptionSets(); +#endif + // These are the current value number for the memory implicit variables while // doing value numbering. These are the value numbers under the "liberal" interpretation // of memory values; the "conservative" interpretation needs no VN, since every access of diff --git a/src/coreclr/jit/valuenum.cpp b/src/coreclr/jit/valuenum.cpp index d6939cf905393..aa15ed2747089 100644 --- a/src/coreclr/jit/valuenum.cpp +++ b/src/coreclr/jit/valuenum.cpp @@ -6793,6 +6793,7 @@ void Compiler::fgValueNumber() #ifdef DEBUG JitTestCheckVN(); + fgDebugCheckExceptionSets(); #endif // DEBUG fgVNPassesCompleted++; @@ -10956,6 +10957,51 @@ void Compiler::fgValueNumberAddExceptionSet(GenTree* tree) } #ifdef DEBUG +//------------------------------------------------------------------------ +// fgDebugCheckExceptionSets: Verify the exception sets on trees. +// +// This function checks that the node's exception set is a superset of +// the exception sets of its operands. +// +void Compiler::fgDebugCheckExceptionSets() +{ + struct ExceptionSetsChecker + { + static void CheckTree(GenTree* tree, ValueNumStore* vnStore) + { + assert(tree->gtVNPair.BothDefined()); + + ValueNumPair operandsExcSet = vnStore->VNPForEmptyExcSet(); + tree->VisitOperands([&](GenTree* operand) -> GenTree::VisitResult { + + CheckTree(operand, vnStore); + operandsExcSet = vnStore->VNPUnionExcSet(operand->gtVNPair, operandsExcSet); + + return GenTree::VisitResult::Continue; + }); + + // Currently, we fail to properly maintain the exception sets for trees with user + // calls or assignments. + if ((tree->gtFlags & (GTF_ASG | GTF_CALL)) != 0) + { + return; + } + + ValueNumPair nodeExcSet = vnStore->VNPExceptionSet(tree->gtVNPair); + assert(vnStore->VNExcIsSubset(nodeExcSet.GetLiberal(), operandsExcSet.GetLiberal())); + assert(vnStore->VNExcIsSubset(nodeExcSet.GetConservative(), operandsExcSet.GetConservative())); + } + }; + + for (BasicBlock* const block : Blocks()) + { + for (Statement* const stmt : block->Statements()) + { + ExceptionSetsChecker::CheckTree(stmt->GetRootNode(), vnStore); + } + } +} + // This method asserts that SSA name constraints specified are satisfied. // Until we figure out otherwise, all VN's are assumed to be liberal. // TODO-Cleanup: new JitTestLabels for lib vs cons vs both VN classes? From 11bc9ca301eb1df0281531358035d1fb57efd0ff Mon Sep 17 00:00:00 2001 From: SingleAccretion Date: Fri, 7 Jan 2022 04:17:45 +0300 Subject: [PATCH 02/30] Add asserts to catch missing nodes --- src/coreclr/jit/valuenum.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/coreclr/jit/valuenum.cpp b/src/coreclr/jit/valuenum.cpp index aa15ed2747089..9c836bddb5d28 100644 --- a/src/coreclr/jit/valuenum.cpp +++ b/src/coreclr/jit/valuenum.cpp @@ -9243,7 +9243,7 @@ void Compiler::fgValueNumberTree(GenTree* tree) break; default: - // The default action is to give the node a new, unique VN. + assert(!"Unhandled node in fgValueNumberTree"); tree->gtVNPair.SetBoth(vnStore->VNForExpr(compCurBB, tree->TypeGet())); break; } @@ -9311,7 +9311,9 @@ void Compiler::fgValueNumberTree(GenTree* tree) } default: + assert(!"Unhandled special node in fgValueNumberTree"); tree->gtVNPair.SetBoth(vnStore->VNForExpr(compCurBB, tree->TypeGet())); + break; } } #ifdef DEBUG From 2a55e6dc451d593b6bfdc8be9a2fd2cb16bc4a67 Mon Sep 17 00:00:00 2001 From: SingleAccretion Date: Sat, 8 Jan 2022 00:11:59 +0300 Subject: [PATCH 03/30] Fix normal VN printing --- src/coreclr/jit/valuenum.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/coreclr/jit/valuenum.cpp b/src/coreclr/jit/valuenum.cpp index 9c836bddb5d28..3ea902a1080ab 100644 --- a/src/coreclr/jit/valuenum.cpp +++ b/src/coreclr/jit/valuenum.cpp @@ -5952,8 +5952,7 @@ void ValueNumStore::vnDumpValWithExc(Compiler* comp, VNFuncApp* valWithExc) GetVNFunc(excVN, &excSeq); printf("norm="); - printf(FMT_VN, normVN); - vnDump(comp, normVN); + comp->vnPrint(normVN, 1); printf(", exc="); printf(FMT_VN, excVN); vnDumpExcSeq(comp, &excSeq, true); From 619e3dd759f5981bb235bd578c33230027a51cc1 Mon Sep 17 00:00:00 2001 From: SingleAccretion Date: Fri, 7 Jan 2022 00:02:52 +0300 Subject: [PATCH 04/30] Fix JTRUE VNs --- src/coreclr/jit/valuenum.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/coreclr/jit/valuenum.cpp b/src/coreclr/jit/valuenum.cpp index 3ea902a1080ab..dcd568e093b00 100644 --- a/src/coreclr/jit/valuenum.cpp +++ b/src/coreclr/jit/valuenum.cpp @@ -9230,8 +9230,9 @@ void Compiler::fgValueNumberTree(GenTree* tree) } case GT_JTRUE: - // These nodes never need to have a ValueNumber - tree->gtVNPair.SetBoth(ValueNumStore::NoVN); + // This node does not produce values. + tree->gtVNPair = vnStore->VNPWithExc(vnStore->VNPForVoid(), + vnStore->VNPExceptionSet(tree->gtGetOp1()->gtVNPair)); break; case GT_BOX: From cf25d6578880a498191e2104910869c8043a5b87 Mon Sep 17 00:00:00 2001 From: SingleAccretion Date: Fri, 7 Jan 2022 00:09:06 +0300 Subject: [PATCH 05/30] Fix PHI VNs --- src/coreclr/jit/valuenum.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/coreclr/jit/valuenum.cpp b/src/coreclr/jit/valuenum.cpp index dcd568e093b00..8efb35af5c55f 100644 --- a/src/coreclr/jit/valuenum.cpp +++ b/src/coreclr/jit/valuenum.cpp @@ -6812,10 +6812,11 @@ void Compiler::fgValueNumberBlock(BasicBlock* blk) assert(asg->OperIs(GT_ASG)); GenTreeLclVar* newSsaDef = asg->AsOp()->gtGetOp1()->AsLclVar(); + GenTreePhi* phiNode = asg->AsOp()->gtGetOp2()->AsPhi(); ValueNumPair phiVNP; ValueNumPair sameVNP; - for (GenTreePhi::Use& use : asg->AsOp()->gtGetOp2()->AsPhi()->Uses()) + for (GenTreePhi::Use& use : phiNode->Uses()) { GenTreePhiArg* phiArg = use.GetNode()->AsPhiArg(); ValueNum phiArgSsaNumVN = vnStore->VNForIntCon(phiArg->GetSsaNum()); @@ -6880,6 +6881,10 @@ void Compiler::fgValueNumberBlock(BasicBlock* blk) printf(" %s.\n", sameVNP.BothDefined() ? "(all same)" : ""); } #endif // DEBUG + + newSsaDef->gtVNPair = vnStore->VNPForVoid(); + phiNode->gtVNPair = newSsaDefVNP; + asg->gtVNPair = vnStore->VNPForVoid(); } // Now do the same for each MemoryKind. From 22ea6f046a48026f7fc78c9891437456165c4d56 Mon Sep 17 00:00:00 2001 From: SingleAccretion Date: Fri, 7 Jan 2022 00:25:07 +0300 Subject: [PATCH 06/30] Update VNs for "this" ARGPLACE node --- src/coreclr/jit/valuenum.cpp | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/src/coreclr/jit/valuenum.cpp b/src/coreclr/jit/valuenum.cpp index 8efb35af5c55f..5fd8bfe6412da 100644 --- a/src/coreclr/jit/valuenum.cpp +++ b/src/coreclr/jit/valuenum.cpp @@ -9949,14 +9949,12 @@ void Compiler::fgValueNumberCall(GenTreeCall* call) { // First: do value numbering of any argument placeholder nodes in the argument list // (by transferring from the VN of the late arg that they are standing in for...) - unsigned i = 0; - for (GenTreeCall::Use& use : call->Args()) - { - GenTree* arg = use.GetNode(); + + auto updateArgVN = [=](GenTree* arg, unsigned argIndex) { if (arg->OperGet() == GT_ARGPLACE) { // Find the corresponding late arg. - GenTree* lateArg = call->fgArgInfo->GetArgNode(i); + GenTree* lateArg = call->fgArgInfo->GetArgNode(argIndex); assert(lateArg->gtVNPair.BothDefined()); arg->gtVNPair = lateArg->gtVNPair; #ifdef DEBUG @@ -9970,7 +9968,19 @@ void Compiler::fgValueNumberCall(GenTreeCall* call) } #endif } - i++; + }; + + unsigned argIndex = 0; + if (call->gtCallThisArg != nullptr) + { + updateArgVN(call->gtCallThisArg->GetNode(), argIndex); + argIndex++; + } + + for (GenTreeCall::Use& use : call->Args()) + { + updateArgVN(use.GetNode(), argIndex); + argIndex++; } if (call->gtCallType == CT_HELPER) From e00348e1526acdce341eb4974bcf2f439843342d Mon Sep 17 00:00:00 2001 From: SingleAccretion Date: Fri, 7 Jan 2022 00:36:08 +0300 Subject: [PATCH 07/30] Tolerate missing VNs on PHI_ARGs We do not update them after numbering the loops. (Though perhaps we should) --- src/coreclr/jit/valuenum.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/coreclr/jit/valuenum.cpp b/src/coreclr/jit/valuenum.cpp index 5fd8bfe6412da..7c0e626d4daa4 100644 --- a/src/coreclr/jit/valuenum.cpp +++ b/src/coreclr/jit/valuenum.cpp @@ -10986,13 +10986,17 @@ void Compiler::fgDebugCheckExceptionSets() { static void CheckTree(GenTree* tree, ValueNumStore* vnStore) { - assert(tree->gtVNPair.BothDefined()); + // We will fail to VN some PHI_ARGs - their values may not + // be known at the point we number them because of loops. + assert(tree->gtVNPair.BothDefined() || tree->OperIs(GT_PHI_ARG)); ValueNumPair operandsExcSet = vnStore->VNPForEmptyExcSet(); tree->VisitOperands([&](GenTree* operand) -> GenTree::VisitResult { CheckTree(operand, vnStore); - operandsExcSet = vnStore->VNPUnionExcSet(operand->gtVNPair, operandsExcSet); + + ValueNumPair operandVNP = operand->gtVNPair.BothDefined() ? operand->gtVNPair : vnStore->VNPForVoid(); + operandsExcSet = vnStore->VNPUnionExcSet(operandVNP, operandsExcSet); return GenTree::VisitResult::Continue; }); From 4595f6efa117eece8cf65cb5137b287ca278ed84 Mon Sep 17 00:00:00 2001 From: SingleAccretion Date: Fri, 7 Jan 2022 00:49:30 +0300 Subject: [PATCH 08/30] Tolerate unreachable blocks --- src/coreclr/jit/valuenum.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/coreclr/jit/valuenum.cpp b/src/coreclr/jit/valuenum.cpp index 7c0e626d4daa4..a083a1ed309ef 100644 --- a/src/coreclr/jit/valuenum.cpp +++ b/src/coreclr/jit/valuenum.cpp @@ -11018,6 +11018,12 @@ void Compiler::fgDebugCheckExceptionSets() { for (Statement* const stmt : block->Statements()) { + // Exclude statements VN hasn't visited for whichever reason... + if (stmt->GetRootNode()->GetVN(VNK_Liberal) == ValueNumStore::NoVN) + { + continue; + } + ExceptionSetsChecker::CheckTree(stmt->GetRootNode(), vnStore); } } From d15e056d8b54aa2ecf41d4e5c86c8625cc88155f Mon Sep 17 00:00:00 2001 From: SingleAccretion Date: Fri, 7 Jan 2022 01:09:27 +0300 Subject: [PATCH 09/30] Fix exception sets for VNF_PtrTo VNFuncs --- src/coreclr/jit/valuenum.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/coreclr/jit/valuenum.cpp b/src/coreclr/jit/valuenum.cpp index a083a1ed309ef..e303ed35386e8 100644 --- a/src/coreclr/jit/valuenum.cpp +++ b/src/coreclr/jit/valuenum.cpp @@ -9116,8 +9116,7 @@ void Compiler::fgValueNumberTree(GenTree* tree) if (newVN != ValueNumStore::NoVN) { // We don't care about differences between liberal and conservative for pointer values. - newVN = vnStore->VNWithExc(newVN, excSetPair.GetLiberal()); - tree->gtVNPair.SetBoth(newVN); + tree->gtVNPair = vnStore->VNPWithExc(ValueNumPair(newVN, newVN), excSetPair); } else { From cb819f3364ce697b6b1d8a48f95b118425a4710d Mon Sep 17 00:00:00 2001 From: SingleAccretion Date: Fri, 7 Jan 2022 22:38:01 +0300 Subject: [PATCH 10/30] Add VNUniqueWithExc --- src/coreclr/jit/valuenum.cpp | 28 ++++++++++++++++++++++++++++ src/coreclr/jit/valuenum.h | 3 +++ 2 files changed, 31 insertions(+) diff --git a/src/coreclr/jit/valuenum.cpp b/src/coreclr/jit/valuenum.cpp index e303ed35386e8..20e699dd38de7 100644 --- a/src/coreclr/jit/valuenum.cpp +++ b/src/coreclr/jit/valuenum.cpp @@ -1423,6 +1423,34 @@ ValueNumPair ValueNumStore::VNPMakeNormalUniquePair(ValueNumPair vnp) return ValueNumPair(VNMakeNormalUnique(vnp.GetLiberal()), VNMakeNormalUnique(vnp.GetConservative())); } +//------------------------------------------------------------------------------------ +// VNUniqueWithExc: +// +// Arguments: +// type - The type for the unique Value Number +// vnExcSet - The Value Number for the exception set. +// +// Return Value: +// - VN representing a "new, unique" value, with +// the exceptions contained in "vnExcSet". +// +ValueNum ValueNumStore::VNUniqueWithExc(var_types type, ValueNum vnExcSet) +{ + ValueNum normVN = VNForExpr(m_pComp->compCurBB, type); + + if (vnExcSet == VNForEmptyExcSet()) + { + return normVN; + } + +#ifdef DEBUG + VNFuncApp excSetFunc; + assert(GetVNFunc(vnExcSet, &excSetFunc) && (excSetFunc.m_func == VNF_ExcSetCons)); +#endif // DEBUG + + return VNWithExc(normVN, vnExcSet); +} + //-------------------------------------------------------------------------------- // VNNormalValue: - Returns a Value Number that represents the result for the // normal (non-exceptional) evaluation for the expression. diff --git a/src/coreclr/jit/valuenum.h b/src/coreclr/jit/valuenum.h index 289e09fb688b1..cd27c14a5cba9 100644 --- a/src/coreclr/jit/valuenum.h +++ b/src/coreclr/jit/valuenum.h @@ -528,6 +528,9 @@ class ValueNumStore // Keeps any Exception set values ValueNumPair VNPMakeNormalUniquePair(ValueNumPair vnp); + // A new unique value with the given exception set. + ValueNum VNUniqueWithExc(var_types type, ValueNum vnExcSet); + // 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 From f30effa424812767fc00a7728308a57805fad4fa Mon Sep 17 00:00:00 2001 From: SingleAccretion Date: Fri, 7 Jan 2022 19:12:52 +0300 Subject: [PATCH 11/30] Add VNPUniqueWithExc --- src/coreclr/jit/valuenum.cpp | 30 ++++++++++++++++++++++++++++++ src/coreclr/jit/valuenum.h | 3 +++ 2 files changed, 33 insertions(+) diff --git a/src/coreclr/jit/valuenum.cpp b/src/coreclr/jit/valuenum.cpp index 20e699dd38de7..003cd5b7e0748 100644 --- a/src/coreclr/jit/valuenum.cpp +++ b/src/coreclr/jit/valuenum.cpp @@ -1451,6 +1451,36 @@ ValueNum ValueNumStore::VNUniqueWithExc(var_types type, ValueNum vnExcSet) return VNWithExc(normVN, vnExcSet); } +//------------------------------------------------------------------------------------ +// VNPUniqueWithExc: +// +// Arguments: +// type - The type for the unique Value Numbers +// vnExcSet - The Value Number Pair for the exception set. +// +// Return Value: +// - VN Pair representing a "new, unique" value (liberal and conservative +// values will be equal), with the exceptions contained in "vnpExcSet". +// +// Notes: - We use the same unique value number both for liberal and conservative +// portions of the pair to save memory (it would not be useful to make +// them different). +// +ValueNumPair ValueNumStore::VNPUniqueWithExc(var_types type, ValueNumPair vnpExcSet) +{ +#ifdef DEBUG + VNFuncApp excSetFunc; + assert((GetVNFunc(vnpExcSet.GetLiberal(), &excSetFunc) && (excSetFunc.m_func == VNF_ExcSetCons)) || + (vnpExcSet.GetLiberal() == VNForEmptyExcSet())); + assert((GetVNFunc(vnpExcSet.GetConservative(), &excSetFunc) && (excSetFunc.m_func == VNF_ExcSetCons)) || + (vnpExcSet.GetConservative() == VNForEmptyExcSet())); +#endif // DEBUG + + ValueNum normVN = VNForExpr(m_pComp->compCurBB, type); + + return VNPWithExc(ValueNumPair(normVN, normVN), vnpExcSet); +} + //-------------------------------------------------------------------------------- // VNNormalValue: - Returns a Value Number that represents the result for the // normal (non-exceptional) evaluation for the expression. diff --git a/src/coreclr/jit/valuenum.h b/src/coreclr/jit/valuenum.h index cd27c14a5cba9..ce4c5b538b999 100644 --- a/src/coreclr/jit/valuenum.h +++ b/src/coreclr/jit/valuenum.h @@ -531,6 +531,9 @@ class ValueNumStore // A new unique value with the given exception set. ValueNum VNUniqueWithExc(var_types type, ValueNum vnExcSet); + // A new unique VN pair with the given exception set pair. + ValueNumPair VNPUniqueWithExc(var_types type, ValueNumPair vnpExcSet); + // 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 From cd68e0467cf97aed64fc114239d587c3cfdd5b42 Mon Sep 17 00:00:00 2001 From: SingleAccretion Date: Fri, 7 Jan 2022 22:38:10 +0300 Subject: [PATCH 12/30] Fix arrays --- src/coreclr/jit/compiler.h | 8 +-- src/coreclr/jit/valuenum.cpp | 123 ++++++++++++++++++----------------- 2 files changed, 66 insertions(+), 65 deletions(-) diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index 61b8e4788208d..7fbd360f2ae7e 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -5432,7 +5432,7 @@ class Compiler // Requires that "tree" is a GT_IND marked as an array index, and that its address argument // has been parsed to yield the other input arguments. If evaluation of the address - // can raise exceptions, those should be captured in the exception set "excVN." + // can raise exceptions, those should be captured in the exception set "addrXvnp". // Assumes that "elemTypeEq" is the (equivalence class rep) of the array element type. // Marks "tree" with the VN for H[elemTypeEq][arrVN][inx][fldSeq] (for the liberal VN; a new unique // VN for the conservative VN.) Also marks the tree's argument as the address of an array element. @@ -5443,14 +5443,14 @@ class Compiler CORINFO_CLASS_HANDLE elemTypeEq, ValueNum arrVN, ValueNum inxVN, - ValueNum excVN, + ValueNumPair addrXvnp, FieldSeqNode* fldSeq); - // Requires "funcApp" to be a VNF_PtrToArrElem, and "addrXvn" to represent the exception set thrown + // Requires "funcApp" to be a VNF_PtrToArrElem, and "addrXvnp" to represent the exception set thrown // by evaluating the array index expression "tree". Returns the value number resulting from // dereferencing the array in the current GcHeap state. If "tree" is non-null, it must be the // "GT_IND" that does the dereference, and it is given the returned value number. - ValueNum fgValueNumberArrIndexVal(GenTree* tree, struct VNFuncApp* funcApp, ValueNum addrXvn); + ValueNum fgValueNumberArrIndexVal(GenTree* tree, VNFuncApp* funcApp, ValueNumPair addrXvnp); // Compute the value number for a byref-exposed load of the given type via the given pointerVN. ValueNum fgValueNumberByrefExposedLoad(var_types type, ValueNum pointerVN); diff --git a/src/coreclr/jit/valuenum.cpp b/src/coreclr/jit/valuenum.cpp index 003cd5b7e0748..fec30f04ce5f5 100644 --- a/src/coreclr/jit/valuenum.cpp +++ b/src/coreclr/jit/valuenum.cpp @@ -4396,21 +4396,21 @@ ValueNum Compiler::fgValueNumberArrIndexAssign(CORINFO_CLASS_HANDLE elemTypeEq, return vnStore->VNForMapStore(fgCurMemoryVN[GcHeap], elemTypeEqVN, newValAtArrType); } -ValueNum Compiler::fgValueNumberArrIndexVal(GenTree* tree, VNFuncApp* pFuncApp, ValueNum addrXvn) +ValueNum Compiler::fgValueNumberArrIndexVal(GenTree* tree, VNFuncApp* pFuncApp, ValueNumPair addrXvnp) { assert(vnStore->IsVNHandle(pFuncApp->m_args[0])); CORINFO_CLASS_HANDLE arrElemTypeEQ = CORINFO_CLASS_HANDLE(vnStore->ConstantValue(pFuncApp->m_args[0])); ValueNum arrVN = pFuncApp->m_args[1]; ValueNum inxVN = pFuncApp->m_args[2]; FieldSeqNode* fldSeq = vnStore->FieldSeqVNToFieldSeq(pFuncApp->m_args[3]); - return fgValueNumberArrIndexVal(tree, arrElemTypeEQ, arrVN, inxVN, addrXvn, fldSeq); + return fgValueNumberArrIndexVal(tree, arrElemTypeEQ, arrVN, inxVN, addrXvnp, fldSeq); } ValueNum Compiler::fgValueNumberArrIndexVal(GenTree* tree, CORINFO_CLASS_HANDLE elemTypeEq, ValueNum arrVN, ValueNum inxVN, - ValueNum excVN, + ValueNumPair addrXvnp, FieldSeqNode* fldSeq) { assert(tree == nullptr || tree->OperIsIndir()); @@ -4430,7 +4430,7 @@ ValueNum Compiler::fgValueNumberArrIndexVal(GenTree* tree, JITDUMP(" *** Not a proper arrray access encountered in fgValueNumberArrIndexVal\n"); // a new unique value number - selectedElem = vnStore->VNForExpr(compCurBB, elemTyp); + selectedElem = vnStore->VNForExpr(compCurBB, indType); #ifdef DEBUG if (verbose) @@ -4441,7 +4441,7 @@ ValueNum Compiler::fgValueNumberArrIndexVal(GenTree* tree, if (tree != nullptr) { - tree->gtVNPair.SetBoth(selectedElem); + tree->gtVNPair = vnStore->VNPWithExc(ValueNumPair(selectedElem, selectedElem), addrXvnp); } } else @@ -4480,7 +4480,7 @@ ValueNum Compiler::fgValueNumberArrIndexVal(GenTree* tree, elemTyp = vnStore->TypeOfVN(selectedElem); } selectedElem = vnStore->VNApplySelectorsTypeCheck(selectedElem, indType, elemStructSize); - selectedElem = vnStore->VNWithExc(selectedElem, excVN); + selectedElem = vnStore->VNWithExc(selectedElem, addrXvnp.GetLiberal()); #ifdef DEBUG if (verbose && (selectedElem != wholeElem)) @@ -4492,10 +4492,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())); + tree->gtVNPair.SetConservative(vnStore->VNUniqueWithExc(tree->TypeGet(), addrXvnp.GetConservative())); } } @@ -8228,7 +8225,7 @@ void Compiler::fgValueNumberBlockAssignment(GenTree* tree) else if (srcAddrFuncApp.m_func == VNF_PtrToArrElem) { ValueNum elemLib = - fgValueNumberArrIndexVal(nullptr, &srcAddrFuncApp, vnStore->VNForEmptyExcSet()); + fgValueNumberArrIndexVal(nullptr, &srcAddrFuncApp, vnStore->VNPForEmptyExcSet()); rhsVNPair.SetLiberal(elemLib); rhsVNPair.SetConservative(vnStore->VNForExpr(compCurBB, lclVarTree->TypeGet())); } @@ -8912,61 +8909,65 @@ void Compiler::fgValueNumberTree(GenTree* tree) // Try to parse it. GenTree* arr = nullptr; addr->ParseArrayAddress(this, &arrInfo, &arr, &inxVN, &fldSeq); - if (arr == nullptr) - { - tree->gtVNPair.SetBoth(vnStore->VNForExpr(compCurBB, tree->TypeGet())); - return; - } - assert(fldSeq != FieldSeqStore::NotAField()); - - // Otherwise... - // Need to form H[arrType][arr][ind][fldSeq] - // Get the array element type equivalence class rep. - CORINFO_CLASS_HANDLE elemTypeEq = EncodeElemType(arrInfo.m_elemType, arrInfo.m_elemStructType); - ValueNum elemTypeEqVN = vnStore->VNForHandle(ssize_t(elemTypeEq), GTF_ICON_CLASS_HDL); - JITDUMP(" VNForHandle(arrElemType: %s) is " FMT_VN "\n", - (arrInfo.m_elemType == TYP_STRUCT) ? eeGetClassName(arrInfo.m_elemStructType) - : varTypeName(arrInfo.m_elemType), - elemTypeEqVN) - - // We take the "VNNormalValue"s here, because if either has exceptional outcomes, they will be captured - // as part of the value of the composite "addr" operation... - ValueNum arrVN = vnStore->VNLiberalNormalValue(arr->gtVNPair); - inxVN = vnStore->VNNormalValue(inxVN); - - // Additionally, relabel the address with a PtrToArrElem value number. - ValueNum fldSeqVN = vnStore->VNForFieldSeq(fldSeq); - ValueNum elemAddr = - vnStore->VNForFunc(TYP_BYREF, VNF_PtrToArrElem, elemTypeEqVN, arrVN, inxVN, fldSeqVN); - - // The aggregate "addr" VN should have had all the exceptions bubble up... - elemAddr = vnStore->VNWithExc(elemAddr, addrXvnp.GetLiberal()); - addr->gtVNPair.SetBoth(elemAddr); + if (arr != nullptr) + { + assert(fldSeq != FieldSeqStore::NotAField()); + + // Need to form H[arrType][arr][ind][fldSeq] + // Get the array element type equivalence class rep. + CORINFO_CLASS_HANDLE elemTypeEq = EncodeElemType(arrInfo.m_elemType, arrInfo.m_elemStructType); + ValueNum elemTypeEqVN = vnStore->VNForHandle(ssize_t(elemTypeEq), GTF_ICON_CLASS_HDL); + JITDUMP(" VNForHandle(arrElemType: %s) is " FMT_VN "\n", + (arrInfo.m_elemType == TYP_STRUCT) ? eeGetClassName(arrInfo.m_elemStructType) + : varTypeName(arrInfo.m_elemType), + elemTypeEqVN); + + // We take the "VNNormalValue"s here, because if either has exceptional outcomes, they will + // be captured as part of the value of the composite "addr" operation... + ValueNum arrVN = vnStore->VNLiberalNormalValue(arr->gtVNPair); + inxVN = vnStore->VNNormalValue(inxVN); + + // Additionally, relabel the address with a PtrToArrElem value number. + ValueNum fldSeqVN = vnStore->VNForFieldSeq(fldSeq); + ValueNum elemAddr = + vnStore->VNForFunc(TYP_BYREF, VNF_PtrToArrElem, elemTypeEqVN, arrVN, inxVN, fldSeqVN); + + // The aggregate "addr" VN should have had all the exceptions bubble up... + addr->gtVNPair = vnStore->VNPWithExc(ValueNumPair(elemAddr, elemAddr), addrXvnp); #ifdef DEBUG - if (verbose) - { - printf(" Relabeled IND_ARR_INDEX address node "); - Compiler::printTreeID(addr); - printf(" with l:" FMT_VN ": ", elemAddr); - vnStore->vnDump(this, elemAddr); - printf("\n"); - if (vnStore->VNNormalValue(elemAddr) != elemAddr) + ValueNum elemAddrWithExc = addr->gtVNPair.GetLiberal(); + if (verbose) { - printf(" [" FMT_VN " is: ", vnStore->VNNormalValue(elemAddr)); - vnStore->vnDump(this, vnStore->VNNormalValue(elemAddr)); - printf("]\n"); + printf(" Relabeled IND_ARR_INDEX address node "); + Compiler::printTreeID(addr); + printf(" with l:" FMT_VN ": ", elemAddrWithExc); + vnStore->vnDump(this, elemAddrWithExc); + printf("\n"); + if (elemAddrWithExc != elemAddr) + { + printf(" [" FMT_VN " is: ", elemAddr); + vnStore->vnDump(this, elemAddr); + printf("]\n"); + } } - } #endif // DEBUG - // We now need to retrieve the value number for the array element value - // and give this value number to the GT_IND node 'tree' - // We do this whenever we have an rvalue, but we don't do it for a - // normal LHS assignment into an array element. - // - if ((tree->gtFlags & GTF_IND_ASG_LHS) == 0) + // We now need to retrieve the value number for the array element value + // and give this value number to the GT_IND node 'tree' + // We do this whenever we have an rvalue, but we don't do it for a + // normal LHS assignment into an array element. + // + if ((tree->gtFlags & GTF_IND_ASG_LHS) == 0) + { + fgValueNumberArrIndexVal(tree, elemTypeEq, arrVN, inxVN, addrXvnp, fldSeq); + } + } + else // An unparseable array expression. { - fgValueNumberArrIndexVal(tree, elemTypeEq, arrVN, inxVN, addrXvnp.GetLiberal(), fldSeq); + if ((tree->gtFlags & GTF_IND_ASG_LHS) == 0) + { + tree->gtVNPair = vnStore->VNPUniqueWithExc(tree->TypeGet(), addrXvnp); + } } } // In general we skip GT_IND nodes on that are the LHS of an assignment. (We labeled these earlier.) @@ -9025,7 +9026,7 @@ void Compiler::fgValueNumberTree(GenTree* tree) } else if (vnStore->GetVNFunc(addrNvnp.GetLiberal(), &funcApp) && (funcApp.m_func == VNF_PtrToArrElem)) { - fgValueNumberArrIndexVal(tree, &funcApp, addrXvnp.GetLiberal()); + fgValueNumberArrIndexVal(tree, &funcApp, addrXvnp); } else if (addr->IsFieldAddr(this, &obj, &staticOffset, &fldSeq2)) { From 4a3258dd8fb49cd7e0e323791b9ef6ea9d262369 Mon Sep 17 00:00:00 2001 From: SingleAccretion Date: Mon, 3 Jan 2022 20:27:08 +0300 Subject: [PATCH 13/30] Consistently give location nodes VNForVoid And always add exception sets for them. This will simplify the exception set propagation code for assignments. --- src/coreclr/jit/valuenum.cpp | 88 ++++++++++++------------------------ 1 file changed, 28 insertions(+), 60 deletions(-) diff --git a/src/coreclr/jit/valuenum.cpp b/src/coreclr/jit/valuenum.cpp index fec30f04ce5f5..a1f6240da6e10 100644 --- a/src/coreclr/jit/valuenum.cpp +++ b/src/coreclr/jit/valuenum.cpp @@ -7524,13 +7524,7 @@ void Compiler::fgValueNumberAssignment(GenTreeOp* tree) } // We have to handle the case where the LHS is a comma. In that case, we don't evaluate the comma, - // so we give it VNForVoid, and we're really interested in the effective value. - GenTree* lhsCommaIter = lhs; - while (lhsCommaIter->OperGet() == GT_COMMA) - { - lhsCommaIter->gtVNPair.SetBoth(vnStore->VNForVoid()); - lhsCommaIter = lhsCommaIter->AsOp()->gtOp2; - } + // and we're really just interested in the effective value. lhs = lhs->gtEffectiveVal(); // Now, record the new VN for an assignment (performing the indicated "state update"). @@ -7687,8 +7681,6 @@ void Compiler::fgValueNumberAssignment(GenTreeOp* tree) // Indicates whether the argument of the IND is the address of a local. bool wasLocal = false; - lhs->gtVNPair = rhsVNPair; - VNFuncApp funcApp; ValueNum argVN = arg->gtVNPair.GetLiberal(); @@ -7924,10 +7916,6 @@ void Compiler::fgValueNumberAssignment(GenTreeOp* tree) storeVal, indType); } - // It is not strictly necessary to set the lhs value number, - // but the dumps read better with it set to the 'storeVal' that we just computed - lhs->gtVNPair.SetBoth(storeVal); - // Update the GcHeap value. recordGcHeapStore(tree, newHeapVN DEBUGARG("StoreField")); } @@ -8574,19 +8562,18 @@ void Compiler::fgValueNumberTree(GenTree* tree) { // We have a Def (write) of the LclVar - // TODO-Review: For the short term, we have a workaround for copyblk/initblk. Those that use - // addrSpillTemp will have a statement like "addrSpillTemp = addr(local)." If we previously decided - // that this block operation defines the local, we will have labeled the "local" node as a DEF - // This flag propagates to the "local" on the RHS. So we'll assume that this is correct, - // and treat it as a def (to a new, unique VN). - // + // The below block ensures we give VNs to the fields of + // "CanBeReplacedWithItsField" struct locals. To the numbering + // of block assignments, those appear as untracked locals, but + // we need to give the SSA defs they represent a VN. if (lcl->GetSsaNum() != SsaConfig::RESERVED_SSA_NUM) { ValueNum uniqVN = vnStore->VNForExpr(compCurBB, lcl->TypeGet()); varDsc->GetPerSsaData(lcl->GetSsaNum())->m_vnPair.SetBoth(uniqVN); } - lcl->gtVNPair = ValueNumPair(); // Avoid confusion -- we don't set the VN of a lcl being defined. + // Location nodes get VNForVoid (no exceptions needed). + lcl->gtVNPair = vnStore->VNPForVoid(); } } break; @@ -8628,6 +8615,11 @@ void Compiler::fgValueNumberTree(GenTree* tree) tree->gtVNPair = vnStore->VNPairApplySelectors(lclVNPair, lclFld->GetFieldSeq(), indType); } } + else + { + // A location node (LHS). + lclFld->gtVNPair = vnStore->VNPForVoid(); + } } break; @@ -8712,6 +8704,11 @@ void Compiler::fgValueNumberTree(GenTree* tree) } tree->gtVNPair = clsVarVNPair; } + else + { + // Location nodes get the "Void" VN. + tree->gtVNPair = vnStore->VNPForVoid(); + } break; case GT_MEMORYBARRIER: // Leaf @@ -9079,6 +9076,12 @@ void Compiler::fgValueNumberTree(GenTree* tree) tree->gtVNPair = vnStore->VNPWithExc(tree->gtVNPair, addrXvnp); } } + + // To be able to propagate exception sets, we give location nodes the "Void" VN. + if ((tree->gtFlags & GTF_IND_ASG_LHS) != 0) + { + tree->gtVNPair = vnStore->VNPWithExc(vnStore->VNPForVoid(), addrXvnp); + } } else if (tree->OperGet() == GT_CAST) { @@ -9194,28 +9197,8 @@ void Compiler::fgValueNumberTree(GenTree* tree) { case GT_COMMA: { - ValueNumPair op1vnp; - ValueNumPair op1Xvnp; - vnStore->VNPUnpackExc(tree->AsOp()->gtOp1->gtVNPair, &op1vnp, &op1Xvnp); - ValueNumPair op2vnp; - ValueNumPair op2Xvnp = ValueNumStore::VNPForEmptyExcSet(); - GenTree* op2 = tree->gtGetOp2(); - - if (op2->OperIsIndir() && ((op2->gtFlags & GTF_IND_ASG_LHS) != 0)) - { - // If op2 represents the lhs of an assignment then we give a VNForVoid for the lhs - op2vnp = ValueNumPair(ValueNumStore::VNForVoid(), ValueNumStore::VNForVoid()); - } - else if ((op2->OperGet() == GT_CLS_VAR) && (op2->gtFlags & GTF_CLS_VAR_ASG_LHS)) - { - // If op2 represents the lhs of an assignment then we give a VNForVoid for the lhs - op2vnp = ValueNumPair(ValueNumStore::VNForVoid(), ValueNumStore::VNForVoid()); - } - else - { - vnStore->VNPUnpackExc(op2->gtVNPair, &op2vnp, &op2Xvnp); - } - tree->gtVNPair = vnStore->VNPWithExc(op2vnp, vnStore->VNPExcSetUnion(op1Xvnp, op2Xvnp)); + ValueNumPair op1Xvnp = vnStore->VNPExceptionSet(tree->AsOp()->gtOp1->gtVNPair); + tree->gtVNPair = vnStore->VNPWithExc(tree->AsOp()->gtOp2->gtVNPair, op1Xvnp); } break; @@ -10593,16 +10576,8 @@ void Compiler::fgValueNumberAddExceptionSetForIndirection(GenTree* tree, GenTree // Combine the excChkSet with exception set of op1 ValueNumPair excSetBoth = vnStore->VNPExcSetUnion(excChkSet, vnpBaseExc); - // Retrieve the Normal VN for tree, note that it may be NoVN, so we handle that case - ValueNumPair vnpNorm = vnStore->VNPNormalPair(tree->gtVNPair); - - // For as GT_IND on the lhs of an assignment we will get a NoVN value - if (vnpNorm.GetLiberal() == ValueNumStore::NoVN) - { - // Use the special Void VN value instead. - vnpNorm = vnStore->VNPForVoid(); - } - tree->gtVNPair = vnStore->VNPWithExc(vnpNorm, excSetBoth); + // Retrieve the Normal VN for tree and combine it with the final exception set. + tree->gtVNPair = vnStore->VNPWithExc(vnStore->VNPNormalPair(tree->gtVNPair), excSetBoth); } //-------------------------------------------------------------------------------- @@ -10983,14 +10958,7 @@ void Compiler::fgValueNumberAddExceptionSet(GenTree* tree) // ToDo: model the exceptions for Intrinsics break; - case GT_IND: // Implicit null check. - if ((tree->gtFlags & GTF_IND_ASG_LHS) != 0) - { - // Don't add exception set on LHS of assignment - break; - } - FALLTHROUGH; - + case GT_IND: case GT_BLK: case GT_OBJ: case GT_DYN_BLK: From 7d0d5a309e3595fb212f407f2d4f21171c35e5c5 Mon Sep 17 00:00:00 2001 From: SingleAccretion Date: Fri, 7 Jan 2022 17:26:55 +0300 Subject: [PATCH 14/30] Fix CSE --- src/coreclr/jit/optcse.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/coreclr/jit/optcse.cpp b/src/coreclr/jit/optcse.cpp index b39b2bd1425c4..0d9a9a234c6f1 100644 --- a/src/coreclr/jit/optcse.cpp +++ b/src/coreclr/jit/optcse.cpp @@ -829,7 +829,8 @@ bool Compiler::optValnumCSE_Locate() continue; } - if (ValueNumStore::isReservedVN(tree->GetVN(VNK_Liberal))) + ValueNum valueVN = vnStore->VNNormalValue(tree->GetVN(VNK_Liberal)); + if (ValueNumStore::isReservedVN(valueVN) && (valueVN != ValueNumStore::VNForNull())) { continue; } From e81a5b19c3ce3efd1c565990cb95c03dc4c0b552 Mon Sep 17 00:00:00 2001 From: SingleAccretion Date: Fri, 7 Jan 2022 02:30:17 +0300 Subject: [PATCH 15/30] Fix GT_RETURN --- src/coreclr/jit/valuenum.cpp | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/src/coreclr/jit/valuenum.cpp b/src/coreclr/jit/valuenum.cpp index a1f6240da6e10..a574e3d284922 100644 --- a/src/coreclr/jit/valuenum.cpp +++ b/src/coreclr/jit/valuenum.cpp @@ -9229,18 +9229,6 @@ void Compiler::fgValueNumberTree(GenTree* tree) } break; - case GT_NULLCHECK: - { - // An Explicit null check, produces no value - // But we do persist any execeptions produced by op1 - // - tree->gtVNPair = vnStore->VNPWithExc(vnStore->VNPForVoid(), - vnStore->VNPExceptionSet(tree->AsOp()->gtOp1->gtVNPair)); - // The exception set with VNF_NullPtrExc will be added below - // by fgValueNumberAddExceptionSet - } - break; - case GT_LOCKADD: // Binop noway_assert("LOCKADD should not appear before lowering"); break; @@ -9275,10 +9263,20 @@ void Compiler::fgValueNumberTree(GenTree* tree) break; } + // These unary nodes do not produce values. Note theat for NULLCHECK the + // additional exception will be added below by "fgValueNumberAddExceptionSet". case GT_JTRUE: - // This node does not produce values. - tree->gtVNPair = vnStore->VNPWithExc(vnStore->VNPForVoid(), - vnStore->VNPExceptionSet(tree->gtGetOp1()->gtVNPair)); + case GT_RETURN: + case GT_NULLCHECK: + if (tree->gtGetOp1() != nullptr) + { + tree->gtVNPair = vnStore->VNPWithExc(vnStore->VNPForVoid(), + vnStore->VNPExceptionSet(tree->gtGetOp1()->gtVNPair)); + } + else + { + tree->gtVNPair = vnStore->VNPForVoid(); + } break; case GT_BOX: From 51ab7525dd9a61bf7d429ab724c859813932470e Mon Sep 17 00:00:00 2001 From: SingleAccretion Date: Fri, 7 Jan 2022 19:13:42 +0300 Subject: [PATCH 16/30] Fix LCLHEAP --- src/coreclr/jit/valuenum.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/coreclr/jit/valuenum.cpp b/src/coreclr/jit/valuenum.cpp index a574e3d284922..ba56e63705412 100644 --- a/src/coreclr/jit/valuenum.cpp +++ b/src/coreclr/jit/valuenum.cpp @@ -9286,6 +9286,14 @@ void Compiler::fgValueNumberTree(GenTree* tree) tree->gtVNPair = tree->gtGetOp1()->gtVNPair; break; + case GT_LCLHEAP: + // We will not be modelling the StackOverflowException for LCLHEAP, just + // give this a new and unique VN and pass through the exceptions. + tree->gtVNPair = + vnStore->VNPUniqueWithExc(tree->TypeGet(), + vnStore->VNPExceptionSet(tree->gtGetOp1()->gtVNPair)); + break; + default: assert(!"Unhandled node in fgValueNumberTree"); tree->gtVNPair.SetBoth(vnStore->VNForExpr(compCurBB, tree->TypeGet())); From 349c9140fa4935c4bce6ffb0424d8163af6bc591 Mon Sep 17 00:00:00 2001 From: SingleAccretion Date: Fri, 7 Jan 2022 03:30:33 +0300 Subject: [PATCH 17/30] Fix GT_ARR_ELEM --- src/coreclr/jit/valuenum.cpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/coreclr/jit/valuenum.cpp b/src/coreclr/jit/valuenum.cpp index ba56e63705412..5219d2b5a378e 100644 --- a/src/coreclr/jit/valuenum.cpp +++ b/src/coreclr/jit/valuenum.cpp @@ -9362,6 +9362,24 @@ void Compiler::fgValueNumberTree(GenTree* tree) break; } + // ARR_ELEM is a bounds-checked address. TODO-CQ: model it precisely. + case GT_ARR_ELEM: + { + GenTreeArrElem* arrElem = tree->AsArrElem(); + + ValueNumPair vnpExcSet = vnStore->VNPExceptionSet(arrElem->gtArrObj->gtVNPair); + for (size_t i = 0; i < arrElem->gtArrRank; i++) + { + vnpExcSet = vnStore->VNPUnionExcSet(arrElem->gtArrInds[i]->gtVNPair, vnpExcSet); + } + + arrElem->gtVNPair = vnStore->VNPUniqueWithExc(arrElem->TypeGet(), vnpExcSet); + + // TODO: model the IndexOutOfRangeException for this node. + fgValueNumberAddExceptionSetForIndirection(arrElem, arrElem->gtArrObj); + } + break; + default: assert(!"Unhandled special node in fgValueNumberTree"); tree->gtVNPair.SetBoth(vnStore->VNForExpr(compCurBB, tree->TypeGet())); From 86f3decaab76b62148ca6f786eb287297252a268 Mon Sep 17 00:00:00 2001 From: SingleAccretion Date: Fri, 7 Jan 2022 03:38:10 +0300 Subject: [PATCH 18/30] Fix unique HWI --- src/coreclr/jit/valuenum.cpp | 34 ++++++++-------------------------- 1 file changed, 8 insertions(+), 26 deletions(-) diff --git a/src/coreclr/jit/valuenum.cpp b/src/coreclr/jit/valuenum.cpp index 5219d2b5a378e..c240ad2e29630 100644 --- a/src/coreclr/jit/valuenum.cpp +++ b/src/coreclr/jit/valuenum.cpp @@ -8382,29 +8382,6 @@ void Compiler::fgValueNumberTree(GenTree* tree) } #endif // FEATURE_SIMD -#ifdef FEATURE_HW_INTRINSICS - if ((JitConfig.JitDisableSimdVN() & 2) == 2) - { - // This Jit Config forces the previous behavior of value numbering for HW Intrinsic nodes - if (oper == GT_HWINTRINSIC) - { - tree->gtVNPair.SetBoth(vnStore->VNForExpr(compCurBB, TYP_UNKNOWN)); - - GenTreeHWIntrinsic* hwIntrinsicNode = tree->AsHWIntrinsic(); - assert(hwIntrinsicNode != nullptr); - - // For safety/correctness we must mutate the global heap valuenumber - // for any HW intrinsic that performs a memory store operation - if (hwIntrinsicNode->OperIsMemoryStore()) - { - fgMutateGcHeap(tree DEBUGARG("HWIntrinsic - MemoryStore")); - } - - return; - } - } -#endif // FEATURE_HW_INTRINSICS - var_types typ = tree->TypeGet(); if (GenTree::OperIsConst(oper)) { @@ -9594,12 +9571,17 @@ void Compiler::fgValueNumberHWIntrinsic(GenTreeHWIntrinsic* tree) fgMutateGcHeap(tree DEBUGARG("HWIntrinsic - MemoryStore")); } - if (tree->GetOperandCount() > 2) + if ((tree->GetOperandCount() > 2) || ((JitConfig.JitDisableSimdVN() & 2) == 2)) { // TODO-CQ: allow intrinsics with > 2 operands to be properly VN'ed, it will // allow use to process things like Vector128.Create(1,2,3,4) etc. - // Generate unique VN for now to retaing previois behavior. - tree->gtVNPair.SetBoth(vnStore->VNForExpr(compCurBB, tree->TypeGet())); + // Generate unique VN for now to retaing previous behavior. + ValueNumPair vnpExcSet = vnStore->VNPForEmptyExcSet(); + for (GenTree* operand : tree->Operands()) + { + vnpExcSet = vnStore->VNPUnionExcSet(operand->gtVNPair, vnpExcSet); + } + tree->gtVNPair = vnStore->VNPUniqueWithExc(tree->TypeGet(), vnpExcSet); return; } From 4e4ca06301c3be5deefd79511abcd142dc740810 Mon Sep 17 00:00:00 2001 From: SingleAccretion Date: Fri, 7 Jan 2022 03:42:00 +0300 Subject: [PATCH 19/30] Fix unique SIMD --- src/coreclr/jit/valuenum.cpp | 34 ++++++++++++++-------------------- 1 file changed, 14 insertions(+), 20 deletions(-) diff --git a/src/coreclr/jit/valuenum.cpp b/src/coreclr/jit/valuenum.cpp index c240ad2e29630..792447ee0e800 100644 --- a/src/coreclr/jit/valuenum.cpp +++ b/src/coreclr/jit/valuenum.cpp @@ -8369,20 +8369,8 @@ bool Compiler::fgValueNumberIsStructReinterpretation(GenTreeLclVarCommon* lhsLcl void Compiler::fgValueNumberTree(GenTree* tree) { genTreeOps oper = tree->OperGet(); + var_types typ = tree->TypeGet(); -#ifdef FEATURE_SIMD - if ((JitConfig.JitDisableSimdVN() & 1) == 1) - { - // This Jit Config forces the previous behavior of value numbering for SIMD nodes - if (oper == GT_SIMD) - { - tree->gtVNPair.SetBoth(vnStore->VNForExpr(compCurBB, TYP_UNKNOWN)); - return; - } - } -#endif // FEATURE_SIMD - - var_types typ = tree->TypeGet(); if (GenTree::OperIsConst(oper)) { // If this is a struct assignment, with a constant rhs, (i,.e. an initBlk), @@ -9434,19 +9422,25 @@ void Compiler::fgValueNumberSimd(GenTreeSIMD* tree) ValueNumPair excSetPair; ValueNumPair normalPair; + if ((tree->GetOperandCount() > 2) || ((JitConfig.JitDisableSimdVN() & 1) == 1)) + { + // We have a SIMD node with 3 or more args. To retain the + // previous behavior, we will generate a unique VN for this case. + excSetPair = ValueNumStore::VNPForEmptyExcSet(); + for (GenTree* operand : tree->Operands()) + { + excSetPair = vnStore->VNPUnionExcSet(operand->gtVNPair, excSetPair); + } + tree->gtVNPair = vnStore->VNPUniqueWithExc(tree->TypeGet(), excSetPair); + return; + } + // There are some SIMD operations that have zero args, i.e. NI_Vector128_Zero if (tree->GetOperandCount() == 0) { excSetPair = ValueNumStore::VNPForEmptyExcSet(); normalPair = vnStore->VNPairForFunc(tree->TypeGet(), simdFunc); } - else if (tree->GetOperandCount() > 2) - { - // We have a SIMD node with 3 or more args. To retain the - // previous behavior, we will generate a unique VN for this case. - tree->gtVNPair.SetBoth(vnStore->VNForExpr(compCurBB, tree->TypeGet())); - return; - } else // SIMD unary or binary operator. { ValueNumPair resvnp = ValueNumPair(); From 32931de7ccb237264ff1851ff3a47d48b6eaeab6 Mon Sep 17 00:00:00 2001 From: SingleAccretion Date: Fri, 7 Jan 2022 03:52:27 +0300 Subject: [PATCH 20/30] Fix GT_SWITCH --- src/coreclr/jit/valuenum.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/coreclr/jit/valuenum.cpp b/src/coreclr/jit/valuenum.cpp index 792447ee0e800..47b82fd5aea6f 100644 --- a/src/coreclr/jit/valuenum.cpp +++ b/src/coreclr/jit/valuenum.cpp @@ -9228,9 +9228,10 @@ void Compiler::fgValueNumberTree(GenTree* tree) break; } - // These unary nodes do not produce values. Note theat for NULLCHECK the + // These unary nodes do not produce values. Note that for NULLCHECK the // additional exception will be added below by "fgValueNumberAddExceptionSet". case GT_JTRUE: + case GT_SWITCH: case GT_RETURN: case GT_NULLCHECK: if (tree->gtGetOp1() != nullptr) From 191b3093abdef3b5e1196b9bcf4eadf29364c5f0 Mon Sep 17 00:00:00 2001 From: SingleAccretion Date: Fri, 7 Jan 2022 04:21:57 +0300 Subject: [PATCH 21/30] Fix CKFINITE --- src/coreclr/jit/valuenum.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/coreclr/jit/valuenum.cpp b/src/coreclr/jit/valuenum.cpp index 47b82fd5aea6f..69577c964090b 100644 --- a/src/coreclr/jit/valuenum.cpp +++ b/src/coreclr/jit/valuenum.cpp @@ -9245,13 +9245,19 @@ void Compiler::fgValueNumberTree(GenTree* tree) } break; + // BOX is a passthrough node (like NOP). case GT_BOX: - // BOX doesn't do anything at this point, the actual object allocation - // and initialization happens separately (and not numbering BOX correctly - // prevents seeing allocation related assertions through it) tree->gtVNPair = tree->gtGetOp1()->gtVNPair; break; + // CKFINITE is a passthrough node just like BOX. We number it conservatively to preserve previous + // behavior. Note that we'll add the exception for it later. + case GT_CKFINITE: + tree->gtVNPair = + vnStore->VNPUniqueWithExc(tree->TypeGet(), + vnStore->VNPExceptionSet(tree->gtGetOp1()->gtVNPair)); + break; + case GT_LCLHEAP: // We will not be modelling the StackOverflowException for LCLHEAP, just // give this a new and unique VN and pass through the exceptions. From 8acc1bd5c1e94eea493a2ee488210ebb228eb4a8 Mon Sep 17 00:00:00 2001 From: SingleAccretion Date: Fri, 7 Jan 2022 16:38:05 +0300 Subject: [PATCH 22/30] Fix HWI loads --- src/coreclr/jit/valuenum.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/coreclr/jit/valuenum.cpp b/src/coreclr/jit/valuenum.cpp index 69577c964090b..c852142e8f3ba 100644 --- a/src/coreclr/jit/valuenum.cpp +++ b/src/coreclr/jit/valuenum.cpp @@ -9594,15 +9594,13 @@ void Compiler::fgValueNumberHWIntrinsic(GenTreeHWIntrinsic* tree) // if (isMemoryLoad) { - ValueNumPair op1vnp; - ValueNumPair op1Xvnp; - vnStore->VNPUnpackExc(tree->Op(1)->gtVNPair, &op1vnp, &op1Xvnp); + ValueNumPair op1vnp = vnStore->VNPNormalPair(tree->Op(1)->gtVNPair); // The addrVN incorporates both op1's ValueNumber and the func operation // The func is used because operations such as LoadLow and LoadHigh perform // different operations, thus need to compute different ValueNumbers // We don't need to encode the result type as it will be encoded by the opcode in 'func' - // + // TODO-Bug: some HWI loads have more than one operand, we need to encode the rest. ValueNum addrVN = vnStore->VNForFunc(TYP_BYREF, func, op1vnp.GetLiberal()); // The address could point anywhere, so it is an ByrefExposed load. @@ -9610,7 +9608,11 @@ void Compiler::fgValueNumberHWIntrinsic(GenTreeHWIntrinsic* tree) ValueNum loadVN = fgValueNumberByrefExposedLoad(tree->TypeGet(), addrVN); tree->gtVNPair.SetLiberal(loadVN); tree->gtVNPair.SetConservative(vnStore->VNForExpr(compCurBB, tree->TypeGet())); - tree->gtVNPair = vnStore->VNPWithExc(tree->gtVNPair, op1Xvnp); + + for (GenTree* operand : tree->Operands()) + { + tree->gtVNPair = vnStore->VNPWithExc(tree->gtVNPair, vnStore->VNPExceptionSet(operand->gtVNPair)); + } fgValueNumberAddExceptionSetForIndirection(tree, tree->Op(1)); return; } From 9cf97cfc2cfb48d598996c3ac9247f5566bea184 Mon Sep 17 00:00:00 2001 From: SingleAccretion Date: Fri, 7 Jan 2022 17:04:08 +0300 Subject: [PATCH 23/30] Fix fgValueNumberAddExceptionSetForIndirection The method does not need to add the exception set for the base address. Additionally, the way it did add the sets, by unioning with normal value numbers, lost all exceptions not coming from the base address. This was fine for the unary loads, but broke the HWI loads that could have exceptions coming from not just the address. --- src/coreclr/jit/valuenum.cpp | 28 ++++++++++++++++++---------- src/coreclr/jit/valuenum.h | 2 ++ 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/src/coreclr/jit/valuenum.cpp b/src/coreclr/jit/valuenum.cpp index c852142e8f3ba..da3dea2989c5f 100644 --- a/src/coreclr/jit/valuenum.cpp +++ b/src/coreclr/jit/valuenum.cpp @@ -1266,6 +1266,17 @@ bool ValueNumStore::VNExcIsSubset(ValueNum vnFullSet, ValueNum vnCandidateSet) } } +//---------------------------------------------------------------------------------------- +// VNPExcIsSubset - Given two exception sets, returns true when both the liberal and +// conservative value numbers of vnpCandidateSet represent subsets of +// the corresponding numbers in vnpFullSet (see VNExcIsSubset). +// +bool ValueNumStore::VNPExcIsSubset(ValueNumPair vnpFullSet, ValueNumPair vnpCandidateSet) +{ + return VNExcIsSubset(vnpFullSet.GetLiberal(), vnpCandidateSet.GetLiberal()) && + VNExcIsSubset(vnpFullSet.GetConservative(), vnpCandidateSet.GetConservative()); +} + //------------------------------------------------------------------------------------- // VNUnpackExc: - Given a ValueNum 'vnWx, return via write back parameters both // the normal and the exception set components. @@ -10574,19 +10585,16 @@ void Compiler::fgValueNumberAddExceptionSetForIndirection(GenTree* tree, GenTree // Create baseVNP, from the values we just computed, baseVNP = ValueNumPair(baseLVN, baseCVN); - // Unpack, Norm,Exc for the tree's op1 VN - ValueNumPair vnpBaseNorm; - ValueNumPair vnpBaseExc; - vnStore->VNPUnpackExc(baseVNP, &vnpBaseNorm, &vnpBaseExc); + // The exceptions in "baseVNP" should have been added to the "tree"'s set already. + assert(vnStore->VNPExcIsSubset(vnStore->VNPExceptionSet(tree->gtVNPair), vnStore->VNPExceptionSet(baseVNP))); - // The Norm VN for op1 is used to create the NullPtrExc - ValueNumPair excChkSet = vnStore->VNPExcSetSingleton(vnStore->VNPairForFunc(TYP_REF, VNF_NullPtrExc, vnpBaseNorm)); + // The normal VN for base address is used to create the NullPtrExc + ValueNumPair vnpBaseNorm = vnStore->VNPNormalPair(baseVNP); - // Combine the excChkSet with exception set of op1 - ValueNumPair excSetBoth = vnStore->VNPExcSetUnion(excChkSet, vnpBaseExc); + ValueNumPair excChkSet = vnStore->VNPExcSetSingleton(vnStore->VNPairForFunc(TYP_REF, VNF_NullPtrExc, vnpBaseNorm)); - // Retrieve the Normal VN for tree and combine it with the final exception set. - tree->gtVNPair = vnStore->VNPWithExc(vnStore->VNPNormalPair(tree->gtVNPair), excSetBoth); + // Add the NullPtrExc to "tree"'s value numbers. + tree->gtVNPair = vnStore->VNPWithExc(tree->gtVNPair, excChkSet); } //-------------------------------------------------------------------------------- diff --git a/src/coreclr/jit/valuenum.h b/src/coreclr/jit/valuenum.h index ce4c5b538b999..6c19327c80037 100644 --- a/src/coreclr/jit/valuenum.h +++ b/src/coreclr/jit/valuenum.h @@ -494,6 +494,8 @@ class ValueNumStore // Both arguments must be either VNForEmptyExcSet() or applications of VNF_ExcSetCons. bool VNExcIsSubset(ValueNum vnFullSet, ValueNum vnCandidateSet); + bool VNPExcIsSubset(ValueNumPair vnpFullSet, ValueNumPair vnpCandidateSet); + // Returns "true" iff "vn" is an application of "VNF_ValWithExc". bool VNHasExc(ValueNum vn) { From fbd4528944f9ecadbd970ff557870641ea0e8781 Mon Sep 17 00:00:00 2001 From: SingleAccretion Date: Fri, 7 Jan 2022 17:33:20 +0300 Subject: [PATCH 24/30] Fix GT_RETFILT --- src/coreclr/jit/valuenum.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/coreclr/jit/valuenum.cpp b/src/coreclr/jit/valuenum.cpp index da3dea2989c5f..a4e4aaccc885e 100644 --- a/src/coreclr/jit/valuenum.cpp +++ b/src/coreclr/jit/valuenum.cpp @@ -9244,6 +9244,7 @@ void Compiler::fgValueNumberTree(GenTree* tree) case GT_JTRUE: case GT_SWITCH: case GT_RETURN: + case GT_RETFILT: case GT_NULLCHECK: if (tree->gtGetOp1() != nullptr) { From d512994a15c261940e8c7209e85bc763926d4427 Mon Sep 17 00:00:00 2001 From: SingleAccretion Date: Fri, 7 Jan 2022 17:38:15 +0300 Subject: [PATCH 25/30] Fix INIT_VAL --- src/coreclr/jit/valuenum.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/coreclr/jit/valuenum.cpp b/src/coreclr/jit/valuenum.cpp index a4e4aaccc885e..a2b1507240f85 100644 --- a/src/coreclr/jit/valuenum.cpp +++ b/src/coreclr/jit/valuenum.cpp @@ -9270,9 +9270,10 @@ void Compiler::fgValueNumberTree(GenTree* tree) vnStore->VNPExceptionSet(tree->gtGetOp1()->gtVNPair)); break; + // These unary nodes will receive a unique VN. + // TODO-CQ: model INIT_VAL properly. case GT_LCLHEAP: - // We will not be modelling the StackOverflowException for LCLHEAP, just - // give this a new and unique VN and pass through the exceptions. + case GT_INIT_VAL: tree->gtVNPair = vnStore->VNPUniqueWithExc(tree->TypeGet(), vnStore->VNPExceptionSet(tree->gtGetOp1()->gtVNPair)); From 0213bc34c5ccadce389e59d140b482ca6890a214 Mon Sep 17 00:00:00 2001 From: SingleAccretion Date: Fri, 7 Jan 2022 17:45:39 +0300 Subject: [PATCH 26/30] Fix DYN_BLK --- src/coreclr/jit/valuenum.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/coreclr/jit/valuenum.cpp b/src/coreclr/jit/valuenum.cpp index a2b1507240f85..649f8006954ed 100644 --- a/src/coreclr/jit/valuenum.cpp +++ b/src/coreclr/jit/valuenum.cpp @@ -9365,6 +9365,17 @@ void Compiler::fgValueNumberTree(GenTree* tree) } break; + // DYN_BLK is always an L-value. + case GT_DYN_BLK: + assert(!tree->CanCSE()); + tree->gtVNPair = vnStore->VNPForVoid(); + tree->gtVNPair = + vnStore->VNPWithExc(tree->gtVNPair, vnStore->VNPExceptionSet(tree->AsDynBlk()->Addr()->gtVNPair)); + tree->gtVNPair = + vnStore->VNPWithExc(tree->gtVNPair, + vnStore->VNPExceptionSet(tree->AsDynBlk()->gtDynamicSize->gtVNPair)); + break; + default: assert(!"Unhandled special node in fgValueNumberTree"); tree->gtVNPair.SetBoth(vnStore->VNForExpr(compCurBB, tree->TypeGet())); From 529a8dce9f09b8344407a2101a252e51e0fb8d87 Mon Sep 17 00:00:00 2001 From: SingleAccretion Date: Fri, 7 Jan 2022 18:24:32 +0300 Subject: [PATCH 27/30] Fix FIELD_LIST --- src/coreclr/jit/valuenum.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/coreclr/jit/valuenum.cpp b/src/coreclr/jit/valuenum.cpp index 649f8006954ed..c3c7f8ae1262f 100644 --- a/src/coreclr/jit/valuenum.cpp +++ b/src/coreclr/jit/valuenum.cpp @@ -9376,6 +9376,16 @@ void Compiler::fgValueNumberTree(GenTree* tree) vnStore->VNPExceptionSet(tree->AsDynBlk()->gtDynamicSize->gtVNPair)); break; + // FIELD_LIST is an R-value that we currently don't model. + case GT_FIELD_LIST: + tree->gtVNPair.SetBoth(vnStore->VNForExpr(compCurBB, tree->TypeGet())); + for (GenTreeFieldList::Use& use : tree->AsFieldList()->Uses()) + { + tree->gtVNPair = + vnStore->VNPWithExc(tree->gtVNPair, vnStore->VNPExceptionSet(use.GetNode()->gtVNPair)); + } + break; + default: assert(!"Unhandled special node in fgValueNumberTree"); tree->gtVNPair.SetBoth(vnStore->VNForExpr(compCurBB, tree->TypeGet())); From 98a061e6a3d6b9e8a29a27e0df3b8de42a1c233d Mon Sep 17 00:00:00 2001 From: SingleAccretion Date: Sat, 8 Jan 2022 01:02:51 +0300 Subject: [PATCH 28/30] De-pessimize CkFinite --- src/coreclr/jit/valuenum.cpp | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/coreclr/jit/valuenum.cpp b/src/coreclr/jit/valuenum.cpp index c3c7f8ae1262f..67260b1dcb9c5 100644 --- a/src/coreclr/jit/valuenum.cpp +++ b/src/coreclr/jit/valuenum.cpp @@ -9257,17 +9257,10 @@ void Compiler::fgValueNumberTree(GenTree* tree) } break; - // BOX is a passthrough node (like NOP). + // BOX and CKFINITE are passthrough nodes (like NOP). We'll add the exception for the latter later. case GT_BOX: - tree->gtVNPair = tree->gtGetOp1()->gtVNPair; - break; - - // CKFINITE is a passthrough node just like BOX. We number it conservatively to preserve previous - // behavior. Note that we'll add the exception for it later. case GT_CKFINITE: - tree->gtVNPair = - vnStore->VNPUniqueWithExc(tree->TypeGet(), - vnStore->VNPExceptionSet(tree->gtGetOp1()->gtVNPair)); + tree->gtVNPair = tree->gtGetOp1()->gtVNPair; break; // These unary nodes will receive a unique VN. From 02918a3e5f3a308597b1a5157d4a34165fb6560b Mon Sep 17 00:00:00 2001 From: SingleAccretion Date: Sat, 8 Jan 2022 14:12:53 +0300 Subject: [PATCH 29/30] Add a test for HWIs --- .../ExceptionSetsPropagation_Hwi.cs | 40 +++++++++++++++++++ .../ExceptionSetsPropagation_Hwi.csproj | 13 ++++++ 2 files changed, 53 insertions(+) create mode 100644 src/tests/JIT/opt/ValueNumbering/ExceptionSetsPropagation_Hwi.cs create mode 100644 src/tests/JIT/opt/ValueNumbering/ExceptionSetsPropagation_Hwi.csproj diff --git a/src/tests/JIT/opt/ValueNumbering/ExceptionSetsPropagation_Hwi.cs b/src/tests/JIT/opt/ValueNumbering/ExceptionSetsPropagation_Hwi.cs new file mode 100644 index 0000000000000..103f6b6c8547c --- /dev/null +++ b/src/tests/JIT/opt/ValueNumbering/ExceptionSetsPropagation_Hwi.cs @@ -0,0 +1,40 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Runtime.Intrinsics; +using System.Runtime.CompilerServices; + +// We're testing whether HWI nodes with > 2 operands propagate exception sets correctly. +// +class ExceptionSetsPropagation_Hwi +{ + public static int Main() + { + try + { + Problem(-1, false, false); + } + catch (OverflowException) + { + return 100; + } + + return 101; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static bool Problem(int a, bool c1, bool c2) + { + var zero = 0; + c1 = a == 0; + c2 = c1; + + if ((Vector128.Create((int)checked((uint)a), a, a, a).GetElement(0) * zero) + a == 0) + { + return false; + } + + return c2; + } +} diff --git a/src/tests/JIT/opt/ValueNumbering/ExceptionSetsPropagation_Hwi.csproj b/src/tests/JIT/opt/ValueNumbering/ExceptionSetsPropagation_Hwi.csproj new file mode 100644 index 0000000000000..5d8fe22529764 --- /dev/null +++ b/src/tests/JIT/opt/ValueNumbering/ExceptionSetsPropagation_Hwi.csproj @@ -0,0 +1,13 @@ + + + Exe + 1 + + + None + True + + + + + From 6795663260abbcae1b4d31516ebd6da53fea9a46 Mon Sep 17 00:00:00 2001 From: SingleAccretion Date: Sat, 8 Jan 2022 16:33:37 +0300 Subject: [PATCH 30/30] Add a test for LCLHEAP --- .../ExceptionSetsPropagation_LclHeap.il | 75 +++++++++++++++++++ .../ExceptionSetsPropagation_LclHeap.ilproj | 13 ++++ 2 files changed, 88 insertions(+) create mode 100644 src/tests/JIT/opt/ValueNumbering/ExceptionSetsPropagation_LclHeap.il create mode 100644 src/tests/JIT/opt/ValueNumbering/ExceptionSetsPropagation_LclHeap.ilproj diff --git a/src/tests/JIT/opt/ValueNumbering/ExceptionSetsPropagation_LclHeap.il b/src/tests/JIT/opt/ValueNumbering/ExceptionSetsPropagation_LclHeap.il new file mode 100644 index 0000000000000..312eb5dcb545e --- /dev/null +++ b/src/tests/JIT/opt/ValueNumbering/ExceptionSetsPropagation_LclHeap.il @@ -0,0 +1,75 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +.assembly extern xunit.core { } +.assembly extern System.Runtime { } +.assembly extern System.Console { } + +.assembly ExceptionSetsPropagation_LclHeap { } + +.class ExceptionSetsPropagation_LclHeap extends [System.Runtime]System.Object +{ + .method public static int32 Main() + { + .custom instance void [xunit.core]Xunit.FactAttribute::.ctor() = (01 00 00 00) + .entrypoint + + .try + { + ldc.i4 300 + conv.i + call bool ExceptionSetsPropagation_LclHeap::Problem(native int) + pop + leave FAIL + } + catch [System.Runtime]System.OverflowException + { + pop + leave SUCCESS + } + + SUCCESS: + ldc.i4 100 + ret + + FAIL: + ldc.i4 101 + ret + } + + .method private static bool Problem(native int a) + { + .locals (bool c1, bool c2) + + ldarg a + localloc + ldc.i4 0 + conv.i + and + ldarg a + ceq + stloc c1 + + ldloc c1 + stloc c2 + + ldarg a + conv.ovf.i1 + conv.i + localloc + ldc.i4 0 + conv.i + and + ldarg a + ceq + brtrue RET + + ldstr "The expected OverflowException was not thrown!" + call void [System.Console]System.Console::WriteLine(string) + + RET: + ldloc c2 + ret + } +} + diff --git a/src/tests/JIT/opt/ValueNumbering/ExceptionSetsPropagation_LclHeap.ilproj b/src/tests/JIT/opt/ValueNumbering/ExceptionSetsPropagation_LclHeap.ilproj new file mode 100644 index 0000000000000..477cccfe1def0 --- /dev/null +++ b/src/tests/JIT/opt/ValueNumbering/ExceptionSetsPropagation_LclHeap.ilproj @@ -0,0 +1,13 @@ + + + Exe + 1 + + + None + True + + + + +