Skip to content

Commit 33704a5

Browse files
authored
JIT: Skip unnecessary binary VN folding checks (#73919)
For a lot of extremely common binary VN functions we do a series of unnecessary folding checks, in particular VNF_ValWithExc and VNF_ExcSetCons. Introduce a VNForFuncNoFolding and VNPairForFuncNoFolding that bypasses folding and use it in some cases.
1 parent 8e2a059 commit 33704a5

File tree

2 files changed

+82
-18
lines changed

2 files changed

+82
-18
lines changed

src/coreclr/jit/valuenum.cpp

Lines changed: 63 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -992,7 +992,7 @@ int ValueNumStore::EvalComparison(VNFunc vnf, T v0, T v1)
992992
//
993993
ValueNum ValueNumStore::VNExcSetSingleton(ValueNum x)
994994
{
995-
return VNForFunc(TYP_REF, VNF_ExcSetCons, x, VNForEmptyExcSet());
995+
return VNForFuncNoFolding(TYP_REF, VNF_ExcSetCons, x, VNForEmptyExcSet());
996996
}
997997
// Create a ValueNumPair for an exception set singleton for 'xp'
998998
//
@@ -1071,24 +1071,24 @@ ValueNum ValueNumStore::VNExcSetUnion(ValueNum xs0, ValueNum xs1)
10711071
assert(VNCheckAscending(funcXs0.m_args[0], funcXs0.m_args[1]));
10721072

10731073
// add the lower one (from xs0) to the result, advance xs0
1074-
res = VNForFunc(TYP_REF, VNF_ExcSetCons, funcXs0.m_args[0], VNExcSetUnion(funcXs0.m_args[1], xs1));
1074+
res = VNForFuncNoFolding(TYP_REF, VNF_ExcSetCons, funcXs0.m_args[0], VNExcSetUnion(funcXs0.m_args[1], xs1));
10751075
}
10761076
else if (funcXs0.m_args[0] == funcXs1.m_args[0])
10771077
{
10781078
assert(VNCheckAscending(funcXs0.m_args[0], funcXs0.m_args[1]));
10791079
assert(VNCheckAscending(funcXs1.m_args[0], funcXs1.m_args[1]));
10801080

10811081
// Equal elements; add one (from xs0) to the result, advance both sets
1082-
res = VNForFunc(TYP_REF, VNF_ExcSetCons, funcXs0.m_args[0],
1083-
VNExcSetUnion(funcXs0.m_args[1], funcXs1.m_args[1]));
1082+
res = VNForFuncNoFolding(TYP_REF, VNF_ExcSetCons, funcXs0.m_args[0],
1083+
VNExcSetUnion(funcXs0.m_args[1], funcXs1.m_args[1]));
10841084
}
10851085
else
10861086
{
10871087
assert(funcXs0.m_args[0] > funcXs1.m_args[0]);
10881088
assert(VNCheckAscending(funcXs1.m_args[0], funcXs1.m_args[1]));
10891089

10901090
// add the lower one (from xs1) to the result, advance xs1
1091-
res = VNForFunc(TYP_REF, VNF_ExcSetCons, funcXs1.m_args[0], VNExcSetUnion(xs0, funcXs1.m_args[1]));
1091+
res = VNForFuncNoFolding(TYP_REF, VNF_ExcSetCons, funcXs1.m_args[0], VNExcSetUnion(xs0, funcXs1.m_args[1]));
10921092
}
10931093

10941094
return res;
@@ -1610,7 +1610,7 @@ ValueNum ValueNumStore::VNWithExc(ValueNum vn, ValueNum excSet)
16101610
ValueNum vnNorm;
16111611
ValueNum vnX;
16121612
VNUnpackExc(vn, &vnNorm, &vnX);
1613-
return VNForFunc(TypeOfVN(vnNorm), VNF_ValWithExc, vnNorm, VNExcSetUnion(vnX, excSet));
1613+
return VNForFuncNoFolding(TypeOfVN(vnNorm), VNF_ValWithExc, vnNorm, VNExcSetUnion(vnX, excSet));
16141614
}
16151615
}
16161616

@@ -2176,7 +2176,7 @@ ValueNum ValueNumStore::VNForFunc(var_types typ, VNFunc func, ValueNum arg0VN, V
21762176
{
21772177
// In terms of values, a castclass always returns its second argument, the object being cast.
21782178
// The operation may also throw an exception
2179-
ValueNum vnExcSet = VNExcSetSingleton(VNForFunc(TYP_REF, VNF_InvalidCastExc, arg1VN, arg0VN));
2179+
ValueNum vnExcSet = VNExcSetSingleton(VNForFuncNoFolding(TYP_REF, VNF_InvalidCastExc, arg1VN, arg0VN));
21802180
resultVN = VNWithExc(arg1VN, vnExcSet);
21812181
}
21822182
else
@@ -2221,6 +2221,51 @@ ValueNum ValueNumStore::VNForFunc(var_types typ, VNFunc func, ValueNum arg0VN, V
22212221
return resultVN;
22222222
}
22232223

2224+
//----------------------------------------------------------------------------------------
2225+
// VNForFuncNoFolding - Returns the ValueNum associated with
2226+
// 'func'('arg0VN','arg1VN') without doing any folding.
2227+
//
2228+
// Arguments:
2229+
// typ - The type of the resulting ValueNum produced by 'func'
2230+
// func - Any binary VNFunc
2231+
// arg0VN - The ValueNum of the first argument to 'func'
2232+
// arg1VN - The ValueNum of the second argument to 'func'
2233+
//
2234+
// Return Value: - Returns the ValueNum associated with 'func'('arg0VN','arg1VN')
2235+
//
2236+
ValueNum ValueNumStore::VNForFuncNoFolding(var_types typ, VNFunc func, ValueNum arg0VN, ValueNum arg1VN)
2237+
{
2238+
assert(arg0VN != NoVN && arg1VN != NoVN);
2239+
2240+
// Function arguments carry no exceptions.
2241+
assert(arg0VN == VNNormalValue(arg0VN));
2242+
assert(arg1VN == VNNormalValue(arg1VN));
2243+
assert(VNFuncArity(func) == 2);
2244+
2245+
ValueNum resultVN;
2246+
2247+
// Have we already assigned a ValueNum for 'func'('arg0VN','arg1VN') ?
2248+
//
2249+
VNDefFuncApp<2> fstruct(func, arg0VN, arg1VN);
2250+
if (!GetVNFunc2Map()->Lookup(fstruct, &resultVN))
2251+
{
2252+
// Otherwise, Allocate a new ValueNum for 'func'('arg0VN','arg1VN')
2253+
//
2254+
Chunk* const c = GetAllocChunk(typ, CEA_Func2);
2255+
unsigned const offsetWithinChunk = c->AllocVN();
2256+
VNDefFuncAppFlexible* fapp = c->PointerToFuncApp(offsetWithinChunk, 2);
2257+
fapp->m_func = func;
2258+
fapp->m_args[0] = arg0VN;
2259+
fapp->m_args[1] = arg1VN;
2260+
resultVN = c->m_baseVN + offsetWithinChunk;
2261+
2262+
// Record 'resultVN' in the Func2Map
2263+
GetVNFunc2Map()->Set(fstruct, resultVN);
2264+
}
2265+
2266+
return resultVN;
2267+
}
2268+
22242269
//----------------------------------------------------------------------------------------
22252270
// VNForFunc - Returns the ValueNum associated with 'func'('arg0VN','arg1VN','arg2VN')
22262271
// There is a one-to-one relationship between the ValueNum
@@ -7571,8 +7616,8 @@ void Compiler::fgValueNumberBlock(BasicBlock* blk)
75717616
}
75727617
else
75737618
{
7574-
phiVNP = vnStore->VNPairForFunc(newSsaDef->TypeGet(), VNF_Phi,
7575-
ValueNumPair(phiArgSsaNumVN, phiArgSsaNumVN), phiVNP);
7619+
phiVNP = vnStore->VNPairForFuncNoFolding(newSsaDef->TypeGet(), VNF_Phi,
7620+
ValueNumPair(phiArgSsaNumVN, phiArgSsaNumVN), phiVNP);
75767621

75777622
if ((sameVNP.GetLiberal() != phiArgVNP.GetLiberal()) ||
75787623
(sameVNP.GetConservative() != phiArgVNP.GetConservative()))
@@ -7681,7 +7726,7 @@ void Compiler::fgValueNumberBlock(BasicBlock* blk)
76817726
unsigned phiArgSSANum = phiArgs->GetSsaNum();
76827727
ValueNum phiArgSSANumVN = vnStore->VNForIntCon(phiArgSSANum);
76837728
JITDUMP(" Building phi application: $%x = SSA# %d.\n", phiArgSSANumVN, phiArgSSANum);
7684-
phiAppVN = vnStore->VNForFunc(TYP_HEAP, VNF_Phi, phiArgSSANumVN, phiAppVN);
7729+
phiAppVN = vnStore->VNForFuncNoFolding(TYP_HEAP, VNF_Phi, phiArgSSANumVN, phiAppVN);
76857730
JITDUMP(" Building phi application: $%x = phi($%x, $%x).\n", phiAppVN, phiArgSSANumVN,
76867731
oldPhiAppVN);
76877732
phiArgs = phiArgs->m_nextArg;
@@ -7692,8 +7737,8 @@ void Compiler::fgValueNumberBlock(BasicBlock* blk)
76927737
}
76937738
else
76947739
{
7695-
newMemoryVN = vnStore->VNForFunc(TYP_HEAP, VNF_PhiMemoryDef,
7696-
vnStore->VNForHandle(ssize_t(blk), GTF_EMPTY), phiAppVN);
7740+
newMemoryVN = vnStore->VNForFuncNoFolding(TYP_HEAP, VNF_PhiMemoryDef,
7741+
vnStore->VNForHandle(ssize_t(blk), GTF_EMPTY), phiAppVN);
76977742
}
76987743
}
76997744
GetMemoryPerSsaData(blk->bbMemorySsaNumIn[memoryKind])->m_vnPair.SetLiberal(newMemoryVN);
@@ -10659,13 +10704,13 @@ void Compiler::fgValueNumberAddExceptionSetForDivision(GenTree* tree)
1065910704
}
1066010705
if (needArithmeticExcLib)
1066110706
{
10662-
vnpArithmExc.SetLiberal(
10663-
vnStore->VNExcSetSingleton(vnStore->VNForFunc(TYP_REF, VNF_ArithmeticExc, vnOp1NormLib, vnOp2NormLib)));
10707+
vnpArithmExc.SetLiberal(vnStore->VNExcSetSingleton(
10708+
vnStore->VNForFuncNoFolding(TYP_REF, VNF_ArithmeticExc, vnOp1NormLib, vnOp2NormLib)));
1066410709
}
1066510710
if (needArithmeticExcCon)
1066610711
{
10667-
vnpArithmExc.SetConservative(
10668-
vnStore->VNExcSetSingleton(vnStore->VNForFunc(TYP_REF, VNF_ArithmeticExc, vnOp1NormLib, vnOp2NormCon)));
10712+
vnpArithmExc.SetConservative(vnStore->VNExcSetSingleton(
10713+
vnStore->VNForFuncNoFolding(TYP_REF, VNF_ArithmeticExc, vnOp1NormLib, vnOp2NormCon)));
1066910714
}
1067010715

1067110716
// Combine vnpDivZeroExc with the exception set of tree
@@ -10776,8 +10821,8 @@ void Compiler::fgValueNumberAddExceptionSetForBoundsCheck(GenTree* tree)
1077610821

1077710822
// Construct the exception set for bounds check
1077810823
ValueNumPair boundsChkExcSet = vnStore->VNPExcSetSingleton(
10779-
vnStore->VNPairForFunc(TYP_REF, VNF_IndexOutOfRangeExc, vnStore->VNPNormalPair(vnpIndex),
10780-
vnStore->VNPNormalPair(vnpArrLen)));
10824+
vnStore->VNPairForFuncNoFolding(TYP_REF, VNF_IndexOutOfRangeExc, vnStore->VNPNormalPair(vnpIndex),
10825+
vnStore->VNPNormalPair(vnpArrLen)));
1078110826

1078210827
// Combine the new Overflow exception with the original exception set of tree
1078310828
ValueNumPair newExcSet = vnStore->VNPExcSetUnion(vnpTreeExc, boundsChkExcSet);

src/coreclr/jit/valuenum.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -633,6 +633,9 @@ class ValueNumStore
633633
ValueNum VNForFunc(
634634
var_types typ, VNFunc func, ValueNum op1VNwx, ValueNum op2VNwx, ValueNum op3VNwx, ValueNum op4VNwx);
635635

636+
// Skip all folding checks.
637+
ValueNum VNForFuncNoFolding(var_types typ, VNFunc func, ValueNum op1VNwx, ValueNum op2VNwx);
638+
636639
ValueNum VNForMapSelect(ValueNumKind vnk, var_types type, ValueNum map, ValueNum index);
637640

638641
ValueNum VNForMapPhysicalSelect(ValueNumKind vnk, var_types type, ValueNum map, unsigned offset, unsigned size);
@@ -702,6 +705,22 @@ class ValueNumStore
702705

703706
return ValueNumPair(liberalFuncVN, conservativeFuncVN);
704707
}
708+
ValueNumPair VNPairForFuncNoFolding(var_types typ, VNFunc func, ValueNumPair op1VN, ValueNumPair op2VN)
709+
{
710+
ValueNum liberalFuncVN = VNForFuncNoFolding(typ, func, op1VN.GetLiberal(), op2VN.GetLiberal());
711+
ValueNum conservativeFuncVN;
712+
713+
if (op1VN.BothEqual() && op2VN.BothEqual())
714+
{
715+
conservativeFuncVN = liberalFuncVN;
716+
}
717+
else
718+
{
719+
conservativeFuncVN = VNForFuncNoFolding(typ, func, op1VN.GetConservative(), op2VN.GetConservative());
720+
}
721+
722+
return ValueNumPair(liberalFuncVN, conservativeFuncVN);
723+
}
705724
ValueNumPair VNPairForFunc(var_types typ, VNFunc func, ValueNumPair op1VN, ValueNumPair op2VN, ValueNumPair op3VN)
706725
{
707726
ValueNum liberalFuncVN = VNForFunc(typ, func, op1VN.GetLiberal(), op2VN.GetLiberal(), op3VN.GetLiberal());

0 commit comments

Comments
 (0)