-
Notifications
You must be signed in to change notification settings - Fork 5.1k
Constant folding for SIMD comparisons #85584
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
d1f693d
00fd532
999ea40
83aaf74
ac2a191
3c3f791
28b759f
6c87055
18091a3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6812,6 +6812,47 @@ ValueNum EvaluateBinarySimd(ValueNumStore* vns, | |
} | ||
#endif // TARGET_XARCH | ||
|
||
case TYP_BOOL: | ||
{ | ||
assert((oper == GT_EQ) || (oper == GT_NE)); | ||
|
||
var_types vn1Type = vns->TypeOfVN(arg0VN); | ||
var_types vn2Type = vns->TypeOfVN(arg1VN); | ||
|
||
assert((vn1Type == vn2Type) && varTypeIsSIMD(vn1Type)); | ||
assert(!varTypeIsFloating(baseType)); | ||
|
||
ValueNum packed = EvaluateBinarySimd(vns, GT_EQ, scalar, vn1Type, baseType, arg0VN, arg1VN); | ||
bool allBitsSet = false; | ||
if (vn1Type == TYP_SIMD8) | ||
{ | ||
allBitsSet = GetConstantSimd8(vns, baseType, packed).IsAllBitsSet(); | ||
} | ||
else if (vn1Type == TYP_SIMD12) | ||
{ | ||
allBitsSet = GetConstantSimd12(vns, baseType, packed).IsAllBitsSet(); | ||
} | ||
else if (vn1Type == TYP_SIMD16) | ||
{ | ||
allBitsSet = GetConstantSimd16(vns, baseType, packed).IsAllBitsSet(); | ||
} | ||
#if defined(TARGET_XARCH) | ||
else if (vn1Type == TYP_SIMD32) | ||
{ | ||
allBitsSet = GetConstantSimd32(vns, baseType, packed).IsAllBitsSet(); | ||
} | ||
else if (vn1Type == TYP_SIMD64) | ||
{ | ||
allBitsSet = GetConstantSimd64(vns, baseType, packed).IsAllBitsSet(); | ||
} | ||
#endif | ||
else | ||
{ | ||
unreached(); | ||
} | ||
return vns->VNForIntCon(oper == GT_EQ ? allBitsSet : !allBitsSet); | ||
} | ||
|
||
default: | ||
{ | ||
unreached(); | ||
|
@@ -7167,6 +7208,43 @@ ValueNum ValueNumStore::EvalHWIntrinsicFunBinary(var_types type, | |
|
||
switch (ni) | ||
{ | ||
#ifdef TARGET_ARM64 | ||
case NI_Vector64_op_Equality: | ||
case NI_Vector128_op_Equality: | ||
case NI_Vector64_EqualsAll: | ||
case NI_Vector128_EqualsAll: | ||
#else | ||
case NI_Vector128_op_Equality: | ||
case NI_Vector256_op_Equality: | ||
case NI_Vector512_op_Equality: | ||
case NI_Vector128_EqualsAll: | ||
case NI_Vector256_EqualsAll: | ||
case NI_Vector512_EqualsAll: | ||
#endif | ||
{ | ||
if (!varTypeIsFloating(baseType)) | ||
{ | ||
return EvaluateBinarySimd(this, GT_EQ, /* scalar */ false, type, baseType, arg0VN, arg1VN); | ||
} | ||
break; | ||
} | ||
|
||
#ifdef TARGET_ARM64 | ||
case NI_Vector64_op_Inequality: | ||
case NI_Vector128_op_Inequality: | ||
#else | ||
case NI_Vector128_op_Inequality: | ||
case NI_Vector256_op_Inequality: | ||
case NI_Vector512_op_Inequality: | ||
#endif | ||
{ | ||
if (!varTypeIsFloating(baseType)) | ||
{ | ||
return EvaluateBinarySimd(this, GT_NE, /* scalar */ false, type, baseType, arg0VN, arg1VN); | ||
} | ||
break; | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we want to handle Likewise given you've added the support for computing the vector version in order to make There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Those had no hits so I just didn't want to add more code and tests 🙂 Although, even EQ/NE don't have hits, I just found a use case outside. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this is the type of scenario where it’s a core comparison on SIMD and so we want to generally handle it even if our own code doesn’t have any hits today. it’s odd to cover some of the relational comparisons and not the others |
||
|
||
#ifdef TARGET_ARM64 | ||
case NI_AdvSimd_Add: | ||
case NI_AdvSimd_Arm64_Add: | ||
|
@@ -10269,14 +10347,35 @@ void Compiler::fgValueNumberSsaVarDef(GenTreeLclVarCommon* lcl) | |
static bool GetStaticFieldSeqAndAddress(ValueNumStore* vnStore, GenTree* tree, ssize_t* byteOffset, FieldSeq** pFseq) | ||
{ | ||
VNFuncApp funcApp; | ||
if (vnStore->GetVNFunc(tree->gtVNPair.GetLiberal(), &funcApp) && (funcApp.m_func == VNF_PtrToStatic)) | ||
if (vnStore->GetVNFunc(tree->gtVNPair.GetLiberal(), &funcApp)) | ||
{ | ||
FieldSeq* fseq = vnStore->FieldSeqVNToFieldSeq(funcApp.m_args[1]); | ||
if (fseq->GetKind() == FieldSeq::FieldKind::SimpleStatic) | ||
if (funcApp.m_func == VNF_PtrToStatic) | ||
{ | ||
*byteOffset = vnStore->ConstantValue<ssize_t>(funcApp.m_args[2]); | ||
*pFseq = fseq; | ||
return true; | ||
FieldSeq* fseq = vnStore->FieldSeqVNToFieldSeq(funcApp.m_args[1]); | ||
if (fseq->GetKind() == FieldSeq::FieldKind::SimpleStatic) | ||
{ | ||
*byteOffset = vnStore->ConstantValue<ssize_t>(funcApp.m_args[2]); | ||
*pFseq = fseq; | ||
return true; | ||
} | ||
} | ||
else if (funcApp.m_func == VNFunc(GT_ADD)) | ||
{ | ||
// Handle ADD(STATIC_HDL, OFFSET) via VN (the logic in this method mostly works with plain tree nodes) | ||
if (vnStore->IsVNHandle(funcApp.m_args[0]) && | ||
(vnStore->GetHandleFlags(funcApp.m_args[0]) == GTF_ICON_STATIC_HDL) && | ||
vnStore->IsVNConstant(funcApp.m_args[1]) && !vnStore->IsVNHandle(funcApp.m_args[1])) | ||
{ | ||
FieldSeq* fldSeq = vnStore->GetFieldSeqFromAddress(funcApp.m_args[0]); | ||
if (fldSeq != nullptr) | ||
{ | ||
assert(fldSeq->GetKind() == FieldSeq::FieldKind::SimpleStaticKnownAddress); | ||
*pFseq = fldSeq; | ||
*byteOffset = vnStore->CoercedConstantValue<ssize_t>(funcApp.m_args[0]) - fldSeq->GetOffset() + | ||
vnStore->CoercedConstantValue<ssize_t>(funcApp.m_args[1]); | ||
return true; | ||
} | ||
} | ||
} | ||
} | ||
ssize_t val = 0; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
shouldn't this be
EvaluateBinarySimd(vns, oper, ...)
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if it would be simpler to implement this as
EvaluateVector
and then simplify check resultIsAllBitsSet
or!IsZero
Which would also simplify the other relational comparisons
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It makes it harder to check output, doesn't it?
Currently I just pass EQ and then return AllBitsSet or !AllBitsSet depending on source oper
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does it? We have a simple property for any simd_T and it makes it easier to cover the other cases.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That is, if you just evaluate per element you get a result simd_T result and can then just check IsAllBitsSet or IsZero