@@ -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
78187920ValueNum 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 }
0 commit comments