-
Notifications
You must be signed in to change notification settings - Fork 4.8k
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
JIT ARM64-SVE: Add AbsoluteCompare* APIs #102611
Changes from all commits
4327570
1ecb98f
8375ac5
7827d1d
1a2329e
1f1d168
41374dc
b0e49d5
95b8280
5e13610
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 |
---|---|---|
|
@@ -1303,17 +1303,32 @@ GenTree* Lowering::LowerHWIntrinsic(GenTreeHWIntrinsic* node) | |
{ | ||
GenTree* user = use.User(); | ||
// Wrap the intrinsic in ConditionalSelect only if it is not already inside another ConditionalSelect | ||
if (!user->OperIsHWIntrinsic() || (user->AsHWIntrinsic()->GetHWIntrinsicId() != NI_Sve_ConditionalSelect)) | ||
// If it is inside ConditionalSelect, then make sure that it is the `mask` operation of it. | ||
if (!user->OperIsHWIntrinsic(NI_Sve_ConditionalSelect) || | ||
(HWIntrinsicInfo::ReturnsPerElementMask(node->GetHWIntrinsicId()))) | ||
{ | ||
CorInfoType simdBaseJitType = node->GetSimdBaseJitType(); | ||
unsigned simdSize = node->GetSimdSize(); | ||
var_types simdType = Compiler::getSIMDTypeForSize(simdSize); | ||
GenTree* trueMask = comp->gtNewSimdAllTrueMaskNode(simdBaseJitType, simdSize); | ||
GenTree* trueVal = node; | ||
GenTree* falseVal = comp->gtNewZeroConNode(simdType); | ||
GenTree* trueVal = node; | ||
var_types nodeType = simdType; | ||
|
||
if (HWIntrinsicInfo::ReturnsPerElementMask(node->GetHWIntrinsicId())) | ||
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 need to test this out to make sure this is correct. I will pull your branch once #103288 is merged. 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 am seeing the test
This is missing a piece where if the 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. @a74nh, @mikabl-arm - I have fixed code to handle Stress tests are passing: https://gist.github.com/kunalspathak/95ddd4913a6642bcbda7ddff9c33f752 The failure case 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. LGTM |
||
{ | ||
nodeType = TYP_MASK; | ||
|
||
GenTree* trueMaskForOp1 = comp->gtNewSimdAllTrueMaskNode(simdBaseJitType, simdSize); | ||
BlockRange().InsertBefore(node, trueMaskForOp1); | ||
BlockRange().InsertBefore(node, falseVal); | ||
|
||
falseVal = comp->gtNewSimdHWIntrinsicNode(TYP_MASK, trueMaskForOp1, falseVal, | ||
NI_Sve_ConvertVectorToMask, simdBaseJitType, simdSize); | ||
} | ||
|
||
GenTreeHWIntrinsic* condSelNode = | ||
comp->gtNewSimdHWIntrinsicNode(simdType, trueMask, trueVal, falseVal, NI_Sve_ConditionalSelect, | ||
comp->gtNewSimdHWIntrinsicNode(nodeType, trueMask, trueVal, falseVal, NI_Sve_ConditionalSelect, | ||
simdBaseJitType, simdSize); | ||
|
||
BlockRange().InsertBefore(node, trueMask); | ||
|
@@ -3365,6 +3380,32 @@ void Lowering::ContainCheckHWIntrinsic(GenTreeHWIntrinsic* node) | |
} | ||
|
||
// Handle op3 | ||
if (op1->IsMaskAllBitsSet()) | ||
{ | ||
bool isZeroValue = false; | ||
if (op3->IsVectorZero()) | ||
{ | ||
isZeroValue = true; | ||
} | ||
else if (op3->OperIsHWIntrinsic(NI_Sve_ConvertVectorToMask)) | ||
{ | ||
GenTreeHWIntrinsic* gtVectorToMask = op3->AsHWIntrinsic(); | ||
|
||
if (gtVectorToMask->Op(1)->IsMaskAllBitsSet() && gtVectorToMask->Op(2)->IsVectorZero()) | ||
{ | ||
isZeroValue = true; | ||
} | ||
} | ||
|
||
if (isZeroValue) | ||
{ | ||
// When we are merging with zero, we can specialize | ||
// and avoid instantiating the vector constant. | ||
// Do this only if op1 was AllTrueMask | ||
MakeSrcContained(node, op3); | ||
} | ||
} | ||
|
||
if (op3->IsVectorZero() && op1->IsMaskAllBitsSet()) | ||
{ | ||
// When we are merging with zero, we can specialize | ||
|
@@ -3410,6 +3451,22 @@ void Lowering::ContainCheckHWIntrinsic(GenTreeHWIntrinsic* node) | |
MakeSrcContained(node, intrin.op3); | ||
} | ||
break; | ||
case NI_Sve_ConvertVectorToMask: | ||
assert(varTypeIsMask(intrin.op1)); | ||
assert(varTypeIsSIMD(intrin.op2)); | ||
if (intrin.op1->IsMaskAllBitsSet() && intrin.op2->IsVectorZero()) | ||
{ | ||
MakeSrcContained(node, intrin.op2); | ||
} | ||
break; | ||
|
||
case NI_Sve_ConvertMaskToVector: | ||
assert(varTypeIsMask(intrin.op1)); | ||
if (intrin.op1->IsVectorZero()) | ||
{ | ||
MakeSrcContained(node, intrin.op1); | ||
} | ||
break; | ||
|
||
default: | ||
unreached(); | ||
|
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.
Not sure I follow this entirely...
This is stating we need to wrap in a
CndSel
if the user isn't aCndSel
or if it is but we're not the mask operand.The
!user->OperIsHWIntrinsic(NI_Sve_ConditionalSelect)
seems fine with that regard but theHWIntrinsicInfo::ReturnsPerElementMask(node->GetHWIntrinsicId())
doesn't seem to fit.Most notably we can have
mask = CndSel(mask1, mask2, mask3)
orvector CndSel(mask, vector1, vector2)
, but also I would have expected that intrinsics likeAbs(x)
which must be emitted with a mask to needCndSel
regardless of where it appears and only that we could optimize it away in some cases likevector = CndSel(mask, vector1, CndSel(mask, vector2, vector3))
(where the outer and inner cndsel use identical masks that mean the latter CndSel becomes redundant as the computed operands would never be selected anyways).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.
So I would have expected the latter condition to basically be conditioned differently, basically ensuring that intrinsics that require a CndSel wrapper always, optionally trying to fold in the case the mask usages can be detected as redundant
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's better to rewrite the comment to avoid confusion I guess:
The goal of this block of code is to wrap
HWIntrinsic
s which satisfyHWIntrinsicInfo::IsEmbeddedMaskedOperation(intrinsicId))
intoConditionalSelect
. Usually this only needs to be done when the intrinsic is not already wrapped. But this logic doesn't hold when such intrinsic is used as themask
operand forConditionalSelect
-user->AsHWIntrinsic()->GetHWIntrinsicId() != NI_Sve_ConditionalSelect
doesn't hold true any more, but the intrinsic still has to be wrappedConditionalSelect
(all that satisfyHWIntrinsicInfo::IsEmbeddedMaskedOperation(intrinsicId)
have to).