HARDWARE_INTRINSIC(NI_ARM64_SIMD_EQ, Simd, CompareEqual, SimdBinaryOp, INS_fcmeq, INS_cmeq, INS_cmeq, None )
HARDWARE_INTRINSIC(NI_ARM64_SIMD_EQ_ZERO, Simd, CompareEqualZero, SimdUnaryOp, INS_fcmeq, INS_cmeq, INS_cmeq, None )
HARDWARE_INTRINSIC(NI_ARM64_SIMD_GE, Simd, CompareGreaterThanOrEqual, SimdBinaryOp, INS_fcmge, INS_cmge, INS_cmhs, None )
-HARDWARE_INTRINSIC(NI_ARM64_SIMD_GE_ZERO, Simd, CompareGreaterThanOrEqualZero, SimdUnaryOp, INS_fcmge, INS_cmge, INS_invalid, None )
+HARDWARE_INTRINSIC(NI_ARM64_SIMD_GE_ZERO, Simd, CompareGreaterThanOrEqualZero, SimdUnaryOp, INS_fcmge, INS_cmge, INS_invalid, LowerCmpUZero )
HARDWARE_INTRINSIC(NI_ARM64_SIMD_GT, Simd, CompareGreaterThan, SimdBinaryOp, INS_fcmgt, INS_cmgt, INS_cmhi, None )
-HARDWARE_INTRINSIC(NI_ARM64_SIMD_GT_ZERO, Simd, CompareGreaterThanZero, SimdUnaryOp, INS_fcmgt, INS_cmgt, INS_invalid, None )
-HARDWARE_INTRINSIC(NI_ARM64_SIMD_LE_ZERO, Simd, CompareLessThanOrEqualZero, SimdUnaryOp, INS_fcmle, INS_cmle, INS_cmeq, None )
-HARDWARE_INTRINSIC(NI_ARM64_SIMD_LT_ZERO, Simd, CompareLessThanZero, SimdUnaryOp, INS_fcmlt, INS_cmlt, INS_invalid, None )
+HARDWARE_INTRINSIC(NI_ARM64_SIMD_GT_ZERO, Simd, CompareGreaterThanZero, SimdUnaryOp, INS_fcmgt, INS_cmgt, INS_invalid, LowerCmpUZero )
+HARDWARE_INTRINSIC(NI_ARM64_SIMD_LE_ZERO, Simd, CompareLessThanOrEqualZero, SimdUnaryOp, INS_fcmle, INS_cmle, INS_cmeq, LowerCmpUZero )
+HARDWARE_INTRINSIC(NI_ARM64_SIMD_LT_ZERO, Simd, CompareLessThanZero, SimdUnaryOp, INS_fcmlt, INS_cmlt, INS_invalid, LowerCmpUZero )
HARDWARE_INTRINSIC(NI_ARM64_SIMD_TST, Simd, CompareTest, SimdBinaryOp, INS_ctst, INS_ctst, INS_ctst, None )
HARDWARE_INTRINSIC(NI_ARM64_SIMD_Div, Simd, Divide, SimdBinaryOp, INS_fdiv, INS_invalid, INS_invalid, None )
HARDWARE_INTRINSIC(NI_ARM64_SIMD_Negate, Simd, Negate, SimdUnaryOp, INS_fneg, INS_neg, INS_invalid, None )
#include "lower.h"
#include "lsra.h"
+#ifdef FEATURE_HW_INTRINSICS
+#include "hwintrinsicArm64.h"
+#endif
+
//------------------------------------------------------------------------
// IsCallTargetInRange: Can a call target address be encoded in-place?
//
//
void Lowering::LowerHWIntrinsic(GenTreeHWIntrinsic* node)
{
+ auto intrinsicID = node->gtHWIntrinsicId;
+ auto intrinsicInfo = comp->getHWIntrinsicInfo(node->gtHWIntrinsicId);
+
+ if ((intrinsicInfo.flags & HWIntrinsicInfo::LowerCmpUZero) && varTypeIsUnsigned(node->gtSIMDBaseType))
+ {
+ auto setAllVector = node->gtSIMDSize > 8 ? NI_ARM64_SIMD_SetAllVector128 : NI_ARM64_SIMD_SetAllVector64;
+
+ auto origOp1 = node->gtOp.gtOp1;
+
+ switch (intrinsicID)
+ {
+ case NI_ARM64_SIMD_GE_ZERO:
+ // Always true
+ node->gtHWIntrinsicId = setAllVector;
+ node->gtOp.gtOp1 = comp->gtNewLconNode(~0ULL);
+ BlockRange().InsertBefore(node, node->gtOp.gtOp1);
+ BlockRange().Remove(origOp1);
+ break;
+ case NI_ARM64_SIMD_GT_ZERO:
+ // Same as !EQ
+ node->gtOp.gtOp1 =
+ comp->gtNewSimdHWIntrinsicNode(node->TypeGet(), node->gtOp.gtOp1, NI_ARM64_SIMD_EQ_ZERO,
+ node->gtSIMDBaseType, node->gtSIMDSize);
+ node->gtHWIntrinsicId = NI_ARM64_SIMD_BitwiseNot;
+ BlockRange().InsertBefore(node, node->gtOp.gtOp1);
+ break;
+ case NI_ARM64_SIMD_LE_ZERO:
+ // Same as EQ
+ node->gtHWIntrinsicId = NI_ARM64_SIMD_EQ_ZERO;
+ break;
+ case NI_ARM64_SIMD_LT_ZERO:
+ // Always false
+ node->gtHWIntrinsicId = setAllVector;
+ node->gtOp.gtOp1 = comp->gtNewIconNode(0);
+ BlockRange().InsertBefore(node, node->gtOp.gtOp1);
+ BlockRange().Remove(origOp1);
+ break;
+ default:
+ assert(!"Unhandled LowerCmpUZero case");
+ }
+ }
+
ContainCheckHWIntrinsic(node);
}
#endif // FEATURE_HW_INTRINSICS
#endif // FEATURE_SIMD
#ifdef FEATURE_HW_INTRINSICS
-#include "hwintrinsicArm64.h"
//----------------------------------------------------------------------------------------------
// ContainCheckHWIntrinsic: Perform containment analysis for a hardware intrinsic node.
//