Skip to content

Commit a052348

Browse files
jasper-dEgorBo
andauthored
Fold const WithElement to CNS_VEC (#86212)
Co-authored-by: Egor Bogatov <[email protected]>
1 parent c14f0c7 commit a052348

File tree

2 files changed

+158
-17
lines changed

2 files changed

+158
-17
lines changed

src/coreclr/jit/valuenum.cpp

Lines changed: 148 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2648,7 +2648,8 @@ ValueNum ValueNumStore::VNForFunc(var_types typ, VNFunc func, ValueNum arg0VN, V
26482648
assert(arg0VN != NoVN);
26492649
assert(arg1VN != NoVN);
26502650
assert(arg2VN != NoVN);
2651-
assert(VNFuncArity(func) == 3);
2651+
// Some SIMD functions with variable number of arguments are defined with zero arity
2652+
assert((VNFuncArity(func) == 0) || (VNFuncArity(func) == 3));
26522653

26532654
#ifdef DEBUG
26542655
// Function arguments carry no exceptions.
@@ -2664,7 +2665,6 @@ ValueNum ValueNumStore::VNForFunc(var_types typ, VNFunc func, ValueNum arg0VN, V
26642665
}
26652666
assert(arg2VN == VNNormalValue(arg2VN));
26662667
#endif
2667-
assert(VNFuncArity(func) == 3);
26682668

26692669
ValueNum resultVN;
26702670

@@ -7813,7 +7813,109 @@ ValueNum ValueNumStore::EvalHWIntrinsicFunBinary(var_types type,
78137813
}
78147814
return VNForFunc(type, func, arg0VN, arg1VN);
78157815
}
7816+
7817+
ValueNum EvaluateSimdFloatWithElement(ValueNumStore* vns, var_types type, ValueNum arg0VN, int index, float value)
7818+
{
7819+
assert(vns->IsVNConstant(arg0VN));
7820+
assert(static_cast<unsigned>(index) < genTypeSize(type) / genTypeSize(TYP_FLOAT));
7821+
7822+
switch (type)
7823+
{
7824+
case TYP_SIMD8:
7825+
{
7826+
simd8_t cnsVec = vns->GetConstantSimd8(arg0VN);
7827+
cnsVec.f32[index] = value;
7828+
return vns->VNForSimd8Con(cnsVec);
7829+
}
7830+
case TYP_SIMD12:
7831+
{
7832+
simd12_t cnsVec = vns->GetConstantSimd12(arg0VN);
7833+
cnsVec.f32[index] = value;
7834+
return vns->VNForSimd12Con(cnsVec);
7835+
}
7836+
case TYP_SIMD16:
7837+
{
7838+
simd16_t cnsVec = vns->GetConstantSimd16(arg0VN);
7839+
cnsVec.f32[index] = value;
7840+
return vns->VNForSimd16Con(cnsVec);
7841+
}
7842+
#if defined TARGET_XARCH
7843+
case TYP_SIMD32:
7844+
{
7845+
simd32_t cnsVec = vns->GetConstantSimd32(arg0VN);
7846+
cnsVec.f32[index] = value;
7847+
return vns->VNForSimd32Con(cnsVec);
7848+
}
7849+
case TYP_SIMD64:
7850+
{
7851+
simd64_t cnsVec = vns->GetConstantSimd64(arg0VN);
7852+
cnsVec.f32[index] = value;
7853+
return vns->VNForSimd64Con(cnsVec);
7854+
}
7855+
#endif // TARGET_XARCH
7856+
default:
7857+
{
7858+
unreached();
7859+
}
7860+
}
7861+
}
7862+
7863+
ValueNum ValueNumStore::EvalHWIntrinsicFunTernary(var_types type,
7864+
var_types baseType,
7865+
NamedIntrinsic ni,
7866+
VNFunc func,
7867+
ValueNum arg0VN,
7868+
ValueNum arg1VN,
7869+
ValueNum arg2VN,
7870+
bool encodeResultType,
7871+
ValueNum resultTypeVN)
7872+
{
7873+
if (IsVNConstant(arg0VN) && IsVNConstant(arg1VN) && IsVNConstant(arg2VN))
7874+
{
7875+
7876+
switch (ni)
7877+
{
7878+
case NI_Vector128_WithElement:
7879+
#ifdef TARGET_ARM64
7880+
case NI_Vector64_WithElement:
7881+
#else
7882+
case NI_Vector256_WithElement:
7883+
case NI_Vector512_WithElement:
78167884
#endif
7885+
{
7886+
int index = GetConstantInt32(arg1VN);
7887+
7888+
assert(varTypeIsSIMD(type));
7889+
7890+
// No meaningful diffs for other base-types.
7891+
if ((baseType != TYP_FLOAT) || (TypeOfVN(arg0VN) != type) ||
7892+
(static_cast<unsigned>(index) >= (genTypeSize(type) / genTypeSize(baseType))))
7893+
{
7894+
break;
7895+
}
7896+
7897+
float value = GetConstantSingle(arg2VN);
7898+
7899+
return EvaluateSimdFloatWithElement(this, type, arg0VN, index, value);
7900+
}
7901+
default:
7902+
{
7903+
break;
7904+
}
7905+
}
7906+
}
7907+
7908+
if (encodeResultType)
7909+
{
7910+
return VNForFunc(type, func, arg0VN, arg1VN, arg2VN, resultTypeVN);
7911+
}
7912+
else
7913+
{
7914+
return VNForFunc(type, func, arg0VN, arg1VN, arg2VN);
7915+
}
7916+
}
7917+
7918+
#endif // FEATURE_HW_INTRINSICS
78177919

78187920
ValueNum ValueNumStore::EvalMathFuncUnary(var_types typ, NamedIntrinsic gtMathFN, ValueNum arg0VN)
78197921
{
@@ -11475,9 +11577,11 @@ void Compiler::fgValueNumberHWIntrinsic(GenTreeHWIntrinsic* tree)
1147511577
ValueNumPair excSetPair = ValueNumStore::VNPForEmptyExcSet();
1147611578
ValueNumPair normalPair = ValueNumPair();
1147711579

11478-
if ((tree->GetOperandCount() > 2) || ((JitConfig.JitDisableSimdVN() & 2) == 2))
11580+
const size_t opCount = tree->GetOperandCount();
11581+
11582+
if ((opCount > 3) || (JitConfig.JitDisableSimdVN() & 2) == 2)
1147911583
{
11480-
// TODO-CQ: allow intrinsics with > 2 operands to be properly VN'ed.
11584+
// TODO-CQ: allow intrinsics with > 3 operands to be properly VN'ed.
1148111585
normalPair = vnStore->VNPairForExpr(compCurBB, tree->TypeGet());
1148211586

1148311587
for (GenTree* operand : tree->Operands())
@@ -11525,7 +11629,7 @@ void Compiler::fgValueNumberHWIntrinsic(GenTreeHWIntrinsic* tree)
1152511629
const bool isVariableNumArgs = HWIntrinsicInfo::lookupNumArgs(intrinsicId) == -1;
1152611630

1152711631
// There are some HWINTRINSICS operations that have zero args, i.e. NI_Vector128_Zero
11528-
if (tree->GetOperandCount() == 0)
11632+
if (opCount == 0)
1152911633
{
1153011634
// Currently we don't have intrinsics with variable number of args with a parameter-less option.
1153111635
assert(!isVariableNumArgs);
@@ -11542,13 +11646,13 @@ void Compiler::fgValueNumberHWIntrinsic(GenTreeHWIntrinsic* tree)
1154211646
assert(vnStore->VNFuncArity(func) == 0);
1154311647
}
1154411648
}
11545-
else // HWINTRINSIC unary or binary operator.
11649+
else // HWINTRINSIC unary or binary or ternary operator.
1154611650
{
1154711651
ValueNumPair op1vnp;
1154811652
ValueNumPair op1Xvnp;
1154911653
getOperandVNs(tree->Op(1), &op1vnp, &op1Xvnp);
1155011654

11551-
if (tree->GetOperandCount() == 1)
11655+
if (opCount == 1)
1155211656
{
1155311657
ValueNum normalLVN = vnStore->EvalHWIntrinsicFunUnary(tree->TypeGet(), tree->GetSimdBaseType(),
1155411658
intrinsicId, func, op1vnp.GetLiberal(),
@@ -11567,17 +11671,44 @@ void Compiler::fgValueNumberHWIntrinsic(GenTreeHWIntrinsic* tree)
1156711671
ValueNumPair op2Xvnp;
1156811672
getOperandVNs(tree->Op(2), &op2vnp, &op2Xvnp);
1156911673

11570-
ValueNum normalLVN =
11571-
vnStore->EvalHWIntrinsicFunBinary(tree->TypeGet(), tree->GetSimdBaseType(), intrinsicId, func,
11572-
op1vnp.GetLiberal(), op2vnp.GetLiberal(), encodeResultType,
11573-
resultTypeVNPair.GetLiberal());
11574-
ValueNum normalCVN =
11575-
vnStore->EvalHWIntrinsicFunBinary(tree->TypeGet(), tree->GetSimdBaseType(), intrinsicId, func,
11576-
op1vnp.GetConservative(), op2vnp.GetConservative(),
11577-
encodeResultType, resultTypeVNPair.GetConservative());
11674+
if (opCount == 2)
11675+
{
11676+
ValueNum normalLVN =
11677+
vnStore->EvalHWIntrinsicFunBinary(tree->TypeGet(), tree->GetSimdBaseType(), intrinsicId, func,
11678+
op1vnp.GetLiberal(), op2vnp.GetLiberal(), encodeResultType,
11679+
resultTypeVNPair.GetLiberal());
11680+
ValueNum normalCVN =
11681+
vnStore->EvalHWIntrinsicFunBinary(tree->TypeGet(), tree->GetSimdBaseType(), intrinsicId, func,
11682+
op1vnp.GetConservative(), op2vnp.GetConservative(),
11683+
encodeResultType, resultTypeVNPair.GetConservative());
1157811684

11579-
normalPair = ValueNumPair(normalLVN, normalCVN);
11580-
excSetPair = vnStore->VNPExcSetUnion(op1Xvnp, op2Xvnp);
11685+
normalPair = ValueNumPair(normalLVN, normalCVN);
11686+
excSetPair = vnStore->VNPExcSetUnion(op1Xvnp, op2Xvnp);
11687+
}
11688+
else
11689+
{
11690+
assert(opCount == 3);
11691+
11692+
ValueNumPair op3vnp;
11693+
ValueNumPair op3Xvnp;
11694+
getOperandVNs(tree->Op(3), &op3vnp, &op3Xvnp);
11695+
11696+
ValueNum normalLVN =
11697+
vnStore->EvalHWIntrinsicFunTernary(tree->TypeGet(), tree->GetSimdBaseType(), intrinsicId, func,
11698+
op1vnp.GetLiberal(), op2vnp.GetLiberal(),
11699+
op3vnp.GetLiberal(), encodeResultType,
11700+
resultTypeVNPair.GetLiberal());
11701+
ValueNum normalCVN =
11702+
vnStore->EvalHWIntrinsicFunTernary(tree->TypeGet(), tree->GetSimdBaseType(), intrinsicId, func,
11703+
op1vnp.GetConservative(), op2vnp.GetConservative(),
11704+
op3vnp.GetConservative(), encodeResultType,
11705+
resultTypeVNPair.GetConservative());
11706+
11707+
normalPair = ValueNumPair(normalLVN, normalCVN);
11708+
11709+
excSetPair = vnStore->VNPExcSetUnion(op1Xvnp, op2Xvnp);
11710+
excSetPair = vnStore->VNPExcSetUnion(excSetPair, op3Xvnp);
11711+
}
1158111712
}
1158211713
}
1158311714
}

src/coreclr/jit/valuenum.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1184,6 +1184,16 @@ class ValueNumStore
11841184
bool encodeResultType,
11851185
ValueNum resultTypeVN);
11861186

1187+
ValueNum EvalHWIntrinsicFunTernary(var_types type,
1188+
var_types baseType,
1189+
NamedIntrinsic ni,
1190+
VNFunc func,
1191+
ValueNum arg0VN,
1192+
ValueNum arg1VN,
1193+
ValueNum arg2VN,
1194+
bool encodeResultType,
1195+
ValueNum resultTypeVN);
1196+
11871197
// Returns "true" iff "vn" represents a function application.
11881198
bool IsVNFunc(ValueNum vn);
11891199

0 commit comments

Comments
 (0)