Skip to content

Add pattern matching for SVE intrinsics that operate on mask operands #114438

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

Merged
merged 15 commits into from
May 20, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions src/coreclr/jit/compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -3132,6 +3132,7 @@ class Compiler

#if defined(TARGET_ARM64)
GenTree* gtNewSimdAllTrueMaskNode(CorInfoType simdBaseJitType, unsigned simdSize);
GenTree* gtNewSimdFalseMaskByteNode(unsigned simdSize);
#endif

GenTree* gtNewSimdBinOpNode(genTreeOps op,
Expand Down Expand Up @@ -6691,6 +6692,15 @@ class Compiler
GenTree* fgMorphHWIntrinsic(GenTreeHWIntrinsic* tree);
GenTree* fgOptimizeHWIntrinsic(GenTreeHWIntrinsic* node);
GenTree* fgOptimizeHWIntrinsicAssociative(GenTreeHWIntrinsic* node);
#if defined(FEATURE_MASKED_HW_INTRINSICS)
GenTreeHWIntrinsic* fgOptimizeForMaskedIntrinsic(GenTreeHWIntrinsic* node);
#endif // FEATURE_MASKED_HW_INTRINSICS
#ifdef TARGET_ARM64
bool canMorphVectorOperandToMask(GenTree* node);
bool canMorphAllVectorOperandsToMasks(GenTreeHWIntrinsic* node);
GenTree* doMorphVectorOperandToMask(GenTree* node, GenTreeHWIntrinsic* parent);
GenTreeHWIntrinsic* fgMorphTryUseAllMaskVariant(GenTreeHWIntrinsic* node);
#endif // TARGET_ARM64
#endif // FEATURE_HW_INTRINSICS
GenTree* fgOptimizeCommutativeArithmetic(GenTreeOp* tree);
GenTree* fgOptimizeRelationalComparisonWithCasts(GenTreeOp* cmp);
Expand Down
66 changes: 66 additions & 0 deletions src/coreclr/jit/hwintrinsic.h
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,11 @@ enum HWIntrinsicFlag : unsigned int
// The intrinsic is a reduce operation.
HW_Flag_ReduceOperation = 0x2000000,

// This intrinsic could be implemented with another intrinsic when it is operating on operands that are all of
// type TYP_MASK, and this other intrinsic will produces a value of this type. Used in morph to convert vector
// operations into mask operations when the intrinsic is operating on mask vectors (mainly bitwise operations).
HW_Flag_HasAllMaskVariant = 0x4000000,

#else
#error Unsupported platform
#endif
Expand Down Expand Up @@ -1133,6 +1138,67 @@ struct HWIntrinsicInfo
}
}

#ifdef FEATURE_MASKED_HW_INTRINSICS
// HasAllMaskVariant: Does the intrinsic have an intrinsic variant that operates on mask types?
//
// Arguments:
// id -- the intrinsic to check for a mask-type variant.
//
// Return Value:
// true when the intrinsic has a mask-type variant, else false
//
static bool HasAllMaskVariant(NamedIntrinsic id)
{
const HWIntrinsicFlag flags = lookupFlags(id);
return (flags & HW_Flag_HasAllMaskVariant) != 0;
}

// GetMaskVariant: Given an intrinsic that has a variant that operates on mask types, return the ID of
// this variant intrinsic. Call HasAllMaskVariant before using this function, as it will
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

may be in a follow-up PR, add assert(HasAllMaskVariant(id));

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

actually, there is a build failure, so can you fix this as well along with fixing the build error?

/__w/1/s/src/coreclr/jit/morpharm64.cpp:99:37: error: comparison of integer expressions of different signedness: ‘size_t’ {aka ‘long unsigned int’} and ‘int’ [-Werror=sign-compare]
     99 |         if (node->GetOperandCount() == numArgs)
        |             ~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~

// assert if no match is found.
//
// Arguments:
// id -- the intrinsic with a mask-type variant.
//
// Return Value:
// The ID of the mask-type variant for the given intrinsic
//
static NamedIntrinsic GetMaskVariant(NamedIntrinsic id)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i know lot of methods in this file don't have method summary, but we try to add them for newly added methods. So please add a line or 2 for them.

{
assert(HasAllMaskVariant(id));
switch (id)
{
case NI_Sve_And:
return NI_Sve_And_Predicates;
case NI_Sve_BitwiseClear:
return NI_Sve_BitwiseClear_Predicates;
case NI_Sve_Xor:
return NI_Sve_Xor_Predicates;
case NI_Sve_Or:
return NI_Sve_Or_Predicates;
case NI_Sve_ZipHigh:
return NI_Sve_ZipHigh_Predicates;
case NI_Sve_ZipLow:
return NI_Sve_ZipLow_Predicates;
case NI_Sve_UnzipOdd:
return NI_Sve_UnzipOdd_Predicates;
case NI_Sve_UnzipEven:
return NI_Sve_UnzipEven_Predicates;
case NI_Sve_TransposeEven:
return NI_Sve_TransposeEven_Predicates;
case NI_Sve_TransposeOdd:
return NI_Sve_TransposeOdd_Predicates;
case NI_Sve_ReverseElement:
return NI_Sve_ReverseElement_Predicates;
case NI_Sve_ConditionalSelect:
return NI_Sve_ConditionalSelect_Predicates;

default:
unreached();
}
}
#endif // FEATURE_MASKED_HW_INTRINSICS

#endif // TARGET_ARM64

static bool HasSpecialSideEffect(NamedIntrinsic id)
Expand Down
16 changes: 15 additions & 1 deletion src/coreclr/jit/hwintrinsicarm64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3341,7 +3341,7 @@ GenTree* Compiler::impSpecialIntrinsic(NamedIntrinsic intrinsic,
}

//------------------------------------------------------------------------
// gtNewSimdEmbeddedMaskNode: Create an embedded mask
// gtNewSimdAllTrueMaskNode: Create an embedded mask with all bits set to true
//
// Arguments:
// simdBaseJitType -- the base jit type of the nodes being masked
Expand All @@ -3355,4 +3355,18 @@ GenTree* Compiler::gtNewSimdAllTrueMaskNode(CorInfoType simdBaseJitType, unsigne
return gtNewSimdHWIntrinsicNode(TYP_MASK, NI_Sve_CreateTrueMaskAll, simdBaseJitType, simdSize);
}

//------------------------------------------------------------------------
// gtNewSimdFalseMaskByteNode: Create an embedded mask with all bits set to false
//
// Arguments:
// simdSize -- the simd size of the nodes being masked
//
// Return Value:
// The mask
//
GenTree* Compiler::gtNewSimdFalseMaskByteNode(unsigned simdSize)
{
return gtNewSimdHWIntrinsicNode(TYP_MASK, NI_Sve_CreateFalseMaskByte, CORINFO_TYPE_UBYTE, simdSize);
}

#endif // FEATURE_HW_INTRINSICS
9 changes: 9 additions & 0 deletions src/coreclr/jit/hwintrinsiccodegenarm64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -702,6 +702,14 @@ void CodeGen::genHWIntrinsic(GenTreeHWIntrinsic* node)
break;
}

case NI_Sve_And_Predicates:
case NI_Sve_BitwiseClear_Predicates:
case NI_Sve_Or_Predicates:
case NI_Sve_Xor_Predicates:
GetEmitter()->emitIns_R_R_R_R(insEmbMask, emitSize, targetReg, maskReg, embMaskOp1Reg,
embMaskOp2Reg, INS_OPTS_SCALABLE_B);
break;

default:
{
GetEmitter()->emitIns_R_R_R_R(insEmbMask, emitSize, targetReg, maskReg, embMaskOp1Reg,
Expand Down Expand Up @@ -2478,6 +2486,7 @@ void CodeGen::genHWIntrinsic(GenTreeHWIntrinsic* node)

case NI_Sve_CreateBreakAfterPropagateMask:
case NI_Sve_CreateBreakBeforePropagateMask:
case NI_Sve_ConditionalSelect_Predicates:
{
GetEmitter()->emitInsSve_R_R_R_R(ins, emitSize, targetReg, op1Reg, op2Reg, op3Reg, INS_OPTS_SCALABLE_B);
break;
Expand Down
Loading
Loading