Skip to content

Commit d0fe41c

Browse files
authored
JIT: Introduce O1K_VN (dotnet#112889)
1 parent e6c5bb4 commit d0fe41c

File tree

2 files changed

+47
-43
lines changed

2 files changed

+47
-43
lines changed

src/coreclr/jit/assertionprop.cpp

Lines changed: 38 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -742,6 +742,10 @@ void Compiler::optPrintAssertion(AssertionDsc* curAssertion, AssertionIndex asse
742742
{
743743
printf("ArrBnds ");
744744
}
745+
else if (curAssertion->op1.kind == O1K_VN)
746+
{
747+
printf("Vn ");
748+
}
745749
else if (curAssertion->op1.kind == O1K_SUBTYPE)
746750
{
747751
printf("Subtype ");
@@ -787,6 +791,10 @@ void Compiler::optPrintAssertion(AssertionDsc* curAssertion, AssertionIndex asse
787791
vnStore->vnDump(this, curAssertion->op1.bnd.vnLen);
788792
printf("]");
789793
}
794+
else if (curAssertion->op1.kind == O1K_VN)
795+
{
796+
printf("[" FMT_VN "]", curAssertion->op1.vn);
797+
}
790798
else if (curAssertion->op1.kind == O1K_BOUND_OPER_BND)
791799
{
792800
printf("Oper_Bnd");
@@ -1534,6 +1542,31 @@ AssertionIndex Compiler::optCreateAssertion(GenTree* op1,
15341542
}
15351543
}
15361544
}
1545+
else
1546+
{
1547+
// Currently, O1K_VN serves as a backup for O1K_LCLVAR (where it's not a local),
1548+
// but long term we should keep O1K_LCLVAR for local assertions only.
1549+
if (!optLocalAssertionProp)
1550+
{
1551+
ValueNum op1VN = optConservativeNormalVN(op1);
1552+
ValueNum op2VN = optConservativeNormalVN(op2);
1553+
1554+
// For TP reasons, limited to 32-bit constants on the op2 side.
1555+
if ((op1VN != ValueNumStore::NoVN) && (op2VN != ValueNumStore::NoVN) && vnStore->IsVNInt32Constant(op2VN) &&
1556+
!vnStore->IsVNHandle(op2VN))
1557+
{
1558+
assert(assertionKind == OAK_EQUAL || assertionKind == OAK_NOT_EQUAL);
1559+
assertion.assertionKind = assertionKind;
1560+
assertion.op1.vn = op1VN;
1561+
assertion.op1.kind = O1K_VN;
1562+
assertion.op2.vn = op2VN;
1563+
assertion.op2.kind = O2K_CONST_INT;
1564+
assertion.op2.u1.iconVal = vnStore->ConstantValue<int>(op2VN);
1565+
assertion.op2.SetIconFlag(GTF_EMPTY);
1566+
return optAddAssertion(&assertion);
1567+
}
1568+
}
1569+
}
15371570

15381571
DONE_ASSERTION:
15391572
return optFinalizeCreatingAssertion(&assertion);
@@ -1831,7 +1864,10 @@ void Compiler::optDebugCheckAssertion(AssertionDsc* assertion)
18311864
break;
18321865
case O1K_ARR_BND:
18331866
// It would be good to check that bnd.vnIdx and bnd.vnLen are valid value numbers.
1867+
assert(!optLocalAssertionProp);
1868+
assert(assertion->assertionKind == OAK_NO_THROW);
18341869
break;
1870+
case O1K_VN:
18351871
case O1K_BOUND_OPER_BND:
18361872
case O1K_BOUND_LOOP_BND:
18371873
case O1K_CONSTANT_LOOP_BND:
@@ -2249,45 +2285,7 @@ AssertionInfo Compiler::optAssertionGenJtrue(GenTree* tree)
22492285
if (vnStore->IsVNCheckedBound(op1VN) && vnStore->IsVNInt32Constant(op2VN))
22502286
{
22512287
assert(relop->OperIs(GT_EQ, GT_NE));
2252-
2253-
int con = vnStore->ConstantValue<int>(op2VN);
2254-
if (con >= 0)
2255-
{
2256-
AssertionDsc dsc;
2257-
2258-
// For arr.Length != 0, we know that 0 is a valid index
2259-
// For arr.Length == con, we know that con - 1 is the greatest valid index
2260-
if (con == 0)
2261-
{
2262-
dsc.assertionKind = OAK_NOT_EQUAL;
2263-
dsc.op1.bnd.vnIdx = vnStore->VNForIntCon(0);
2264-
}
2265-
else
2266-
{
2267-
dsc.assertionKind = OAK_EQUAL;
2268-
dsc.op1.bnd.vnIdx = vnStore->VNForIntCon(con - 1);
2269-
}
2270-
2271-
dsc.op1.vn = op1VN;
2272-
dsc.op1.kind = O1K_ARR_BND;
2273-
dsc.op1.bnd.vnLen = op1VN;
2274-
dsc.op2.vn = vnStore->VNConservativeNormalValue(op2->gtVNPair);
2275-
dsc.op2.kind = O2K_CONST_INT;
2276-
dsc.op2.u1.iconVal = 0;
2277-
dsc.op2.SetIconFlag(GTF_EMPTY);
2278-
2279-
// when con is not zero, create an assertion on the arr.Length == con edge
2280-
// when con is zero, create an assertion on the arr.Length != 0 edge
2281-
AssertionIndex index = optAddAssertion(&dsc);
2282-
if (relop->OperIs(GT_NE) != (con == 0))
2283-
{
2284-
return AssertionInfo::ForNextEdge(index);
2285-
}
2286-
else
2287-
{
2288-
return index;
2289-
}
2290-
}
2288+
return optCreateJtrueAssertions(op1, op2, assertionKind);
22912289
}
22922290
}
22932291

@@ -4061,8 +4059,7 @@ void Compiler::optAssertionProp_RangeProperties(ASSERT_VALARG_TP assertions,
40614059
}
40624060

40634061
// First, analyze possible X ==/!= CNS assertions.
4064-
if (curAssertion->IsConstantInt32Assertion() && (curAssertion->op1.kind == O1K_LCLVAR) &&
4065-
(curAssertion->op1.vn == treeVN))
4062+
if (curAssertion->IsConstantInt32Assertion() && (curAssertion->op1.vn == treeVN))
40664063
{
40674064
if ((curAssertion->assertionKind == OAK_NOT_EQUAL) && (curAssertion->op2.u1.iconVal == 0))
40684065
{

src/coreclr/jit/compiler.h

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7885,6 +7885,7 @@ class Compiler
78857885
{
78867886
O1K_INVALID,
78877887
O1K_LCLVAR,
7888+
O1K_VN,
78887889
O1K_ARR_BND,
78897890
O1K_BOUND_OPER_BND,
78907891
O1K_BOUND_LOOP_BND,
@@ -8009,7 +8010,8 @@ class Compiler
80098010

80108011
bool IsConstantInt32Assertion()
80118012
{
8012-
return ((assertionKind == OAK_EQUAL) || (assertionKind == OAK_NOT_EQUAL)) && (op2.kind == O2K_CONST_INT);
8013+
return ((assertionKind == OAK_EQUAL) || (assertionKind == OAK_NOT_EQUAL)) && (op2.kind == O2K_CONST_INT) &&
8014+
((op1.kind == O1K_LCLVAR) || (op1.kind == O1K_VN));
80138015
}
80148016

80158017
bool CanPropLclVar()
@@ -8029,7 +8031,7 @@ class Compiler
80298031

80308032
bool CanPropBndsCheck()
80318033
{
8032-
return op1.kind == O1K_ARR_BND;
8034+
return (op1.kind == O1K_ARR_BND) || (op1.kind == O1K_VN);
80338035
}
80348036

80358037
bool CanPropSubRange()
@@ -8067,6 +8069,11 @@ class Compiler
80678069
assert(vnBased);
80688070
return (op1.bnd.vnIdx == that->op1.bnd.vnIdx) && (op1.bnd.vnLen == that->op1.bnd.vnLen);
80698071
}
8072+
else if (op1.kind == O1K_VN)
8073+
{
8074+
assert(vnBased);
8075+
return (op1.vn == that->op1.vn);
8076+
}
80708077
else
80718078
{
80728079
return ((vnBased && (op1.vn == that->op1.vn)) ||

0 commit comments

Comments
 (0)