Skip to content

Commit

Permalink
JIT: Skip unnecessary binary VN folding checks (#73919)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
jakobbotsch authored Sep 8, 2022
1 parent 8e2a059 commit 33704a5
Show file tree
Hide file tree
Showing 2 changed files with 82 additions and 18 deletions.
81 changes: 63 additions & 18 deletions src/coreclr/jit/valuenum.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -992,7 +992,7 @@ int ValueNumStore::EvalComparison(VNFunc vnf, T v0, T v1)
//
ValueNum ValueNumStore::VNExcSetSingleton(ValueNum x)
{
return VNForFunc(TYP_REF, VNF_ExcSetCons, x, VNForEmptyExcSet());
return VNForFuncNoFolding(TYP_REF, VNF_ExcSetCons, x, VNForEmptyExcSet());
}
// Create a ValueNumPair for an exception set singleton for 'xp'
//
Expand Down Expand Up @@ -1071,24 +1071,24 @@ ValueNum ValueNumStore::VNExcSetUnion(ValueNum xs0, ValueNum xs1)
assert(VNCheckAscending(funcXs0.m_args[0], funcXs0.m_args[1]));

// add the lower one (from xs0) to the result, advance xs0
res = VNForFunc(TYP_REF, VNF_ExcSetCons, funcXs0.m_args[0], VNExcSetUnion(funcXs0.m_args[1], xs1));
res = VNForFuncNoFolding(TYP_REF, VNF_ExcSetCons, funcXs0.m_args[0], VNExcSetUnion(funcXs0.m_args[1], xs1));
}
else if (funcXs0.m_args[0] == funcXs1.m_args[0])
{
assert(VNCheckAscending(funcXs0.m_args[0], funcXs0.m_args[1]));
assert(VNCheckAscending(funcXs1.m_args[0], funcXs1.m_args[1]));

// Equal elements; add one (from xs0) to the result, advance both sets
res = VNForFunc(TYP_REF, VNF_ExcSetCons, funcXs0.m_args[0],
VNExcSetUnion(funcXs0.m_args[1], funcXs1.m_args[1]));
res = VNForFuncNoFolding(TYP_REF, VNF_ExcSetCons, funcXs0.m_args[0],
VNExcSetUnion(funcXs0.m_args[1], funcXs1.m_args[1]));
}
else
{
assert(funcXs0.m_args[0] > funcXs1.m_args[0]);
assert(VNCheckAscending(funcXs1.m_args[0], funcXs1.m_args[1]));

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

return res;
Expand Down Expand Up @@ -1610,7 +1610,7 @@ ValueNum ValueNumStore::VNWithExc(ValueNum vn, ValueNum excSet)
ValueNum vnNorm;
ValueNum vnX;
VNUnpackExc(vn, &vnNorm, &vnX);
return VNForFunc(TypeOfVN(vnNorm), VNF_ValWithExc, vnNorm, VNExcSetUnion(vnX, excSet));
return VNForFuncNoFolding(TypeOfVN(vnNorm), VNF_ValWithExc, vnNorm, VNExcSetUnion(vnX, excSet));
}
}

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

//----------------------------------------------------------------------------------------
// VNForFuncNoFolding - Returns the ValueNum associated with
// 'func'('arg0VN','arg1VN') without doing any folding.
//
// Arguments:
// typ - The type of the resulting ValueNum produced by 'func'
// func - Any binary VNFunc
// arg0VN - The ValueNum of the first argument to 'func'
// arg1VN - The ValueNum of the second argument to 'func'
//
// Return Value: - Returns the ValueNum associated with 'func'('arg0VN','arg1VN')
//
ValueNum ValueNumStore::VNForFuncNoFolding(var_types typ, VNFunc func, ValueNum arg0VN, ValueNum arg1VN)
{
assert(arg0VN != NoVN && arg1VN != NoVN);

// Function arguments carry no exceptions.
assert(arg0VN == VNNormalValue(arg0VN));
assert(arg1VN == VNNormalValue(arg1VN));
assert(VNFuncArity(func) == 2);

ValueNum resultVN;

// Have we already assigned a ValueNum for 'func'('arg0VN','arg1VN') ?
//
VNDefFuncApp<2> fstruct(func, arg0VN, arg1VN);
if (!GetVNFunc2Map()->Lookup(fstruct, &resultVN))
{
// Otherwise, Allocate a new ValueNum for 'func'('arg0VN','arg1VN')
//
Chunk* const c = GetAllocChunk(typ, CEA_Func2);
unsigned const offsetWithinChunk = c->AllocVN();
VNDefFuncAppFlexible* fapp = c->PointerToFuncApp(offsetWithinChunk, 2);
fapp->m_func = func;
fapp->m_args[0] = arg0VN;
fapp->m_args[1] = arg1VN;
resultVN = c->m_baseVN + offsetWithinChunk;

// Record 'resultVN' in the Func2Map
GetVNFunc2Map()->Set(fstruct, resultVN);
}

return resultVN;
}

//----------------------------------------------------------------------------------------
// VNForFunc - Returns the ValueNum associated with 'func'('arg0VN','arg1VN','arg2VN')
// There is a one-to-one relationship between the ValueNum
Expand Down Expand Up @@ -7571,8 +7616,8 @@ void Compiler::fgValueNumberBlock(BasicBlock* blk)
}
else
{
phiVNP = vnStore->VNPairForFunc(newSsaDef->TypeGet(), VNF_Phi,
ValueNumPair(phiArgSsaNumVN, phiArgSsaNumVN), phiVNP);
phiVNP = vnStore->VNPairForFuncNoFolding(newSsaDef->TypeGet(), VNF_Phi,
ValueNumPair(phiArgSsaNumVN, phiArgSsaNumVN), phiVNP);

if ((sameVNP.GetLiberal() != phiArgVNP.GetLiberal()) ||
(sameVNP.GetConservative() != phiArgVNP.GetConservative()))
Expand Down Expand Up @@ -7681,7 +7726,7 @@ void Compiler::fgValueNumberBlock(BasicBlock* blk)
unsigned phiArgSSANum = phiArgs->GetSsaNum();
ValueNum phiArgSSANumVN = vnStore->VNForIntCon(phiArgSSANum);
JITDUMP(" Building phi application: $%x = SSA# %d.\n", phiArgSSANumVN, phiArgSSANum);
phiAppVN = vnStore->VNForFunc(TYP_HEAP, VNF_Phi, phiArgSSANumVN, phiAppVN);
phiAppVN = vnStore->VNForFuncNoFolding(TYP_HEAP, VNF_Phi, phiArgSSANumVN, phiAppVN);
JITDUMP(" Building phi application: $%x = phi($%x, $%x).\n", phiAppVN, phiArgSSANumVN,
oldPhiAppVN);
phiArgs = phiArgs->m_nextArg;
Expand All @@ -7692,8 +7737,8 @@ void Compiler::fgValueNumberBlock(BasicBlock* blk)
}
else
{
newMemoryVN = vnStore->VNForFunc(TYP_HEAP, VNF_PhiMemoryDef,
vnStore->VNForHandle(ssize_t(blk), GTF_EMPTY), phiAppVN);
newMemoryVN = vnStore->VNForFuncNoFolding(TYP_HEAP, VNF_PhiMemoryDef,
vnStore->VNForHandle(ssize_t(blk), GTF_EMPTY), phiAppVN);
}
}
GetMemoryPerSsaData(blk->bbMemorySsaNumIn[memoryKind])->m_vnPair.SetLiberal(newMemoryVN);
Expand Down Expand Up @@ -10659,13 +10704,13 @@ void Compiler::fgValueNumberAddExceptionSetForDivision(GenTree* tree)
}
if (needArithmeticExcLib)
{
vnpArithmExc.SetLiberal(
vnStore->VNExcSetSingleton(vnStore->VNForFunc(TYP_REF, VNF_ArithmeticExc, vnOp1NormLib, vnOp2NormLib)));
vnpArithmExc.SetLiberal(vnStore->VNExcSetSingleton(
vnStore->VNForFuncNoFolding(TYP_REF, VNF_ArithmeticExc, vnOp1NormLib, vnOp2NormLib)));
}
if (needArithmeticExcCon)
{
vnpArithmExc.SetConservative(
vnStore->VNExcSetSingleton(vnStore->VNForFunc(TYP_REF, VNF_ArithmeticExc, vnOp1NormLib, vnOp2NormCon)));
vnpArithmExc.SetConservative(vnStore->VNExcSetSingleton(
vnStore->VNForFuncNoFolding(TYP_REF, VNF_ArithmeticExc, vnOp1NormLib, vnOp2NormCon)));
}

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

// Construct the exception set for bounds check
ValueNumPair boundsChkExcSet = vnStore->VNPExcSetSingleton(
vnStore->VNPairForFunc(TYP_REF, VNF_IndexOutOfRangeExc, vnStore->VNPNormalPair(vnpIndex),
vnStore->VNPNormalPair(vnpArrLen)));
vnStore->VNPairForFuncNoFolding(TYP_REF, VNF_IndexOutOfRangeExc, vnStore->VNPNormalPair(vnpIndex),
vnStore->VNPNormalPair(vnpArrLen)));

// Combine the new Overflow exception with the original exception set of tree
ValueNumPair newExcSet = vnStore->VNPExcSetUnion(vnpTreeExc, boundsChkExcSet);
Expand Down
19 changes: 19 additions & 0 deletions src/coreclr/jit/valuenum.h
Original file line number Diff line number Diff line change
Expand Up @@ -633,6 +633,9 @@ class ValueNumStore
ValueNum VNForFunc(
var_types typ, VNFunc func, ValueNum op1VNwx, ValueNum op2VNwx, ValueNum op3VNwx, ValueNum op4VNwx);

// Skip all folding checks.
ValueNum VNForFuncNoFolding(var_types typ, VNFunc func, ValueNum op1VNwx, ValueNum op2VNwx);

ValueNum VNForMapSelect(ValueNumKind vnk, var_types type, ValueNum map, ValueNum index);

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

return ValueNumPair(liberalFuncVN, conservativeFuncVN);
}
ValueNumPair VNPairForFuncNoFolding(var_types typ, VNFunc func, ValueNumPair op1VN, ValueNumPair op2VN)
{
ValueNum liberalFuncVN = VNForFuncNoFolding(typ, func, op1VN.GetLiberal(), op2VN.GetLiberal());
ValueNum conservativeFuncVN;

if (op1VN.BothEqual() && op2VN.BothEqual())
{
conservativeFuncVN = liberalFuncVN;
}
else
{
conservativeFuncVN = VNForFuncNoFolding(typ, func, op1VN.GetConservative(), op2VN.GetConservative());
}

return ValueNumPair(liberalFuncVN, conservativeFuncVN);
}
ValueNumPair VNPairForFunc(var_types typ, VNFunc func, ValueNumPair op1VN, ValueNumPair op2VN, ValueNumPair op3VN)
{
ValueNum liberalFuncVN = VNForFunc(typ, func, op1VN.GetLiberal(), op2VN.GetLiberal(), op3VN.GetLiberal());
Expand Down

0 comments on commit 33704a5

Please sign in to comment.