From 1e1d91543ecebc92d598a32f58ed6818c6398709 Mon Sep 17 00:00:00 2001 From: Sebastian Nickolls Date: Wed, 23 Apr 2025 13:19:37 +0000 Subject: [PATCH 1/2] Add SVE2 API skeleton and implement BitwiseClearXor --- src/coreclr/jit/hwintrinsic.cpp | 2 +- src/coreclr/jit/hwintrinsiccodegenarm64.cpp | 6 ++ src/coreclr/jit/hwintrinsiclistarm64sve.h | 11 ++- .../ILLink.Substitutions.NoArmIntrinsics.xml | 6 ++ .../System.Private.CoreLib.Shared.projitems | 2 + .../Arm/Sve2.PlatformNotSupported.cs | 81 +++++++++++++++++++ .../src/System/Runtime/Intrinsics/Arm/Sve2.cs | 81 +++++++++++++++++++ .../ref/System.Runtime.Intrinsics.cs | 22 +++++ .../GenerateHWIntrinsicTests_Arm.cs | 12 +++ .../HardwareIntrinsics/Arm/Shared/Helpers.cs | 5 ++ .../HardwareIntrinsics/Arm/Shared/Program.cs | 1 + .../Arm/Sve2/Program.Sve2.cs | 16 ++++ .../HardwareIntrinsics/Arm/Sve2/Sve2_r.csproj | 20 +++++ .../Arm/Sve2/Sve2_ro.csproj | 20 +++++ 14 files changed, 282 insertions(+), 3 deletions(-) create mode 100644 src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/Sve2.PlatformNotSupported.cs create mode 100644 src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/Sve2.cs create mode 100644 src/tests/JIT/HardwareIntrinsics/Arm/Sve2/Program.Sve2.cs create mode 100644 src/tests/JIT/HardwareIntrinsics/Arm/Sve2/Sve2_r.csproj create mode 100644 src/tests/JIT/HardwareIntrinsics/Arm/Sve2/Sve2_ro.csproj diff --git a/src/coreclr/jit/hwintrinsic.cpp b/src/coreclr/jit/hwintrinsic.cpp index 71e07025dad03c..3e2a5fec80837d 100644 --- a/src/coreclr/jit/hwintrinsic.cpp +++ b/src/coreclr/jit/hwintrinsic.cpp @@ -857,7 +857,7 @@ static const HWIntrinsicIsaRange hwintrinsicIsaRangeArray[] = { { NI_Illegal, NI_Illegal }, // VectorT128 { NI_Illegal, NI_Illegal }, // Rcpc2 { FIRST_NI_Sve, LAST_NI_Sve }, - { NI_Illegal, NI_Illegal }, // Sve2 + { FIRST_NI_Sve2, LAST_NI_Sve2 }, // Sve2 { FIRST_NI_ArmBase_Arm64, LAST_NI_ArmBase_Arm64 }, { FIRST_NI_AdvSimd_Arm64, LAST_NI_AdvSimd_Arm64 }, { NI_Illegal, NI_Illegal }, // Aes_Arm64 diff --git a/src/coreclr/jit/hwintrinsiccodegenarm64.cpp b/src/coreclr/jit/hwintrinsiccodegenarm64.cpp index 9bb7a1e4f39356..cf1f8cca4447cc 100644 --- a/src/coreclr/jit/hwintrinsiccodegenarm64.cpp +++ b/src/coreclr/jit/hwintrinsiccodegenarm64.cpp @@ -2649,6 +2649,12 @@ void CodeGen::genHWIntrinsic(GenTreeHWIntrinsic* node) break; } + case NI_Sve2_BitwiseClearXor: + assert(targetReg == op1Reg); + // Always use the lane size D. It's a bitwise operation so this is fine for all integer vector types. + GetEmitter()->emitIns_R_R_R(ins, emitSize, op1Reg, op2Reg, op3Reg, INS_OPTS_SCALABLE_D); + break; + default: unreached(); } diff --git a/src/coreclr/jit/hwintrinsiclistarm64sve.h b/src/coreclr/jit/hwintrinsiclistarm64sve.h index 9bb76b0ad038a5..54f797376eca04 100644 --- a/src/coreclr/jit/hwintrinsiclistarm64sve.h +++ b/src/coreclr/jit/hwintrinsiclistarm64sve.h @@ -307,8 +307,16 @@ HARDWARE_INTRINSIC(Sve, ZipLow, // ISA Function name SIMD size NumArg Instructions Category Flags // {TYP_BYTE, TYP_UBYTE, TYP_SHORT, TYP_USHORT, TYP_INT, TYP_UINT, TYP_LONG, TYP_ULONG, TYP_FLOAT, TYP_DOUBLE} // *************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** -// Special intrinsics that are generated during importing or lowering +// SVE2 Intrinsics +#define FIRST_NI_Sve2 NI_Sve2_BitwiseClearXor +HARDWARE_INTRINSIC(Sve2, BitwiseClearXor, -1, 3, {INS_sve_bcax, INS_sve_bcax, INS_sve_bcax, INS_sve_bcax, INS_sve_bcax, INS_sve_bcax, INS_sve_bcax, INS_sve_bcax, INS_invalid, INS_invalid}, HW_Category_SIMD, HW_Flag_Scalable|HW_Flag_SpecialCodeGen|HW_Flag_HasRMWSemantics) +#define LAST_NI_Sve2 NI_Sve2_BitwiseClearXor +// *************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** +// ISA Function name SIMD size NumArg Instructions Category Flags +// {TYP_BYTE, TYP_UBYTE, TYP_SHORT, TYP_USHORT, TYP_INT, TYP_UINT, TYP_LONG, TYP_ULONG, TYP_FLOAT, TYP_DOUBLE} +// *************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** +// Special intrinsics that are generated during importing or lowering #define SPECIAL_NI_Sve NI_Sve_ConditionalExtractAfterLastActiveElementScalar HARDWARE_INTRINSIC(Sve, ConditionalExtractAfterLastActiveElementScalar, 0, 3, {INS_sve_clasta, INS_sve_clasta, INS_sve_clasta, INS_sve_clasta, INS_sve_clasta, INS_sve_clasta, INS_sve_clasta, INS_sve_clasta, INS_sve_clasta, INS_sve_clasta}, HW_Category_Scalar, HW_Flag_Scalable|HW_Flag_SpecialCodeGen|HW_Flag_SpecialImport|HW_Flag_HasRMWSemantics|HW_Flag_ExplicitMaskedOperation|HW_Flag_LowMaskedOperation) HARDWARE_INTRINSIC(Sve, ConditionalExtractLastActiveElementScalar, 0, 3, {INS_sve_clastb, INS_sve_clastb, INS_sve_clastb, INS_sve_clastb, INS_sve_clastb, INS_sve_clastb, INS_sve_clastb, INS_sve_clastb, INS_sve_clastb, INS_sve_clastb}, HW_Category_Scalar, HW_Flag_Scalable|HW_Flag_SpecialCodeGen|HW_Flag_SpecialImport|HW_Flag_HasRMWSemantics|HW_Flag_ExplicitMaskedOperation|HW_Flag_LowMaskedOperation) @@ -326,7 +334,6 @@ HARDWARE_INTRINSIC(Sve, StoreAndZipx2, HARDWARE_INTRINSIC(Sve, StoreAndZipx3, -1, 3, {INS_sve_st3b, INS_sve_st3b, INS_sve_st3h, INS_sve_st3h, INS_sve_st3w, INS_sve_st3w, INS_sve_st3d, INS_sve_st3d, INS_sve_st3w, INS_sve_st3d}, HW_Category_MemoryStore, HW_Flag_Scalable|HW_Flag_SpecialCodeGen|HW_Flag_ExplicitMaskedOperation|HW_Flag_LowMaskedOperation|HW_Flag_NeedsConsecutiveRegisters) HARDWARE_INTRINSIC(Sve, StoreAndZipx4, -1, 3, {INS_sve_st4b, INS_sve_st4b, INS_sve_st4h, INS_sve_st4h, INS_sve_st4w, INS_sve_st4w, INS_sve_st4d, INS_sve_st4d, INS_sve_st4w, INS_sve_st4d}, HW_Category_MemoryStore, HW_Flag_Scalable|HW_Flag_SpecialCodeGen|HW_Flag_ExplicitMaskedOperation|HW_Flag_LowMaskedOperation|HW_Flag_NeedsConsecutiveRegisters) - #endif // FEATURE_HW_INTRINSIC #undef HARDWARE_INTRINSIC diff --git a/src/libraries/System.Private.CoreLib/src/ILLink/ILLink.Substitutions.NoArmIntrinsics.xml b/src/libraries/System.Private.CoreLib/src/ILLink/ILLink.Substitutions.NoArmIntrinsics.xml index 7d05d2b47a61fe..d9da2ff0648052 100644 --- a/src/libraries/System.Private.CoreLib/src/ILLink/ILLink.Substitutions.NoArmIntrinsics.xml +++ b/src/libraries/System.Private.CoreLib/src/ILLink/ILLink.Substitutions.NoArmIntrinsics.xml @@ -57,5 +57,11 @@ + + + + + + diff --git a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems index d3f62e4c34b7d9..8ab6470882cdef 100644 --- a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems +++ b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems @@ -2712,6 +2712,7 @@ + @@ -2723,6 +2724,7 @@ + diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/Sve2.PlatformNotSupported.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/Sve2.PlatformNotSupported.cs new file mode 100644 index 00000000000000..5fe0e2293205a1 --- /dev/null +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/Sve2.PlatformNotSupported.cs @@ -0,0 +1,81 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Diagnostics.CodeAnalysis; +using System.Runtime.CompilerServices; +using System.Runtime.Intrinsics; +using System.Numerics; + +namespace System.Runtime.Intrinsics.Arm +{ + /// + /// This class provides access to the ARM SVE hardware instructions via intrinsics + /// + [Intrinsic] + [CLSCompliant(false)] + [Experimental(Experimentals.ArmSveDiagId, UrlFormat = Experimentals.SharedUrlFormat)] + public abstract class Sve2 : Sve + { + internal Sve2() { } + + public static new bool IsSupported { get => IsSupported; } + + [Intrinsic] + public new abstract class Arm64 : Sve.Arm64 + { + internal Arm64() { } + + public static new bool IsSupported { get => IsSupported; } + } + + // Bitwise clear and exclusive OR + + /// + /// svuint8_t svbcax[_u8](svuint8_t op1, svuint8_t op2, svuint8_t op3) + /// BCAX Ztied1.D, Ztied1.D, Zop2.D, Zop3.D + /// + public static unsafe Vector BitwiseClearXor(Vector xor, Vector value, Vector mask) { throw new PlatformNotSupportedException(); } + + /// + /// svint16_t svbcax[_s16](svint16_t op1, svint16_t op2, svint16_t op3) + /// BCAX Ztied1.D, Ztied1.D, Zop2.D, Zop3.D + /// + public static unsafe Vector BitwiseClearXor(Vector xor, Vector value, Vector mask) { throw new PlatformNotSupportedException(); } + + /// + /// svint32_t svbcax[_s32](svint32_t op1, svint32_t op2, svint32_t op3) + /// BCAX Ztied1.D, Ztied1.D, Zop2.D, Zop3.D + /// + public static unsafe Vector BitwiseClearXor(Vector xor, Vector value, Vector mask) { throw new PlatformNotSupportedException(); } + + /// + /// svint64_t svbcax[_s64](svint64_t op1, svint64_t op2, svint64_t op3) + /// BCAX Ztied1.D, Ztied1.D, Zop2.D, Zop3.D + /// + public static unsafe Vector BitwiseClearXor(Vector xor, Vector value, Vector mask) { throw new PlatformNotSupportedException(); } + + /// + /// svint8_t svbcax[_s8](svint8_t op1, svint8_t op2, svint8_t op3) + /// BCAX Ztied1.D, Ztied1.D, Zop2.D, Zop3.D + /// + public static unsafe Vector BitwiseClearXor(Vector xor, Vector value, Vector mask) { throw new PlatformNotSupportedException(); } + + /// + /// svuint16_t svbcax[_u16](svuint16_t op1, svuint16_t op2, svuint16_t op3) + /// BCAX Ztied1.D, Ztied1.D, Zop2.D, Zop3.D + /// + public static unsafe Vector BitwiseClearXor(Vector xor, Vector value, Vector mask) { throw new PlatformNotSupportedException(); } + + /// + /// svuint32_t svbcax[_u32](svuint32_t op1, svuint32_t op2, svuint32_t op3) + /// BCAX Ztied1.D, Ztied1.D, Zop2.D, Zop3.D + /// + public static unsafe Vector BitwiseClearXor(Vector xor, Vector value, Vector mask) { throw new PlatformNotSupportedException(); } + + /// + /// svuint64_t svbcax[_u64](svuint64_t op1, svuint64_t op2, svuint64_t op3) + /// BCAX Ztied1.D, Ztied1.D, Zop2.D, Zop3.D + /// + public static unsafe Vector BitwiseClearXor(Vector xor, Vector value, Vector mask) { throw new PlatformNotSupportedException(); } + } +} diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/Sve2.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/Sve2.cs new file mode 100644 index 00000000000000..3a6340fb693c8a --- /dev/null +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/Sve2.cs @@ -0,0 +1,81 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Diagnostics.CodeAnalysis; +using System.Runtime.CompilerServices; +using System.Runtime.Intrinsics; +using System.Numerics; + +namespace System.Runtime.Intrinsics.Arm +{ + /// + /// This class provides access to the ARM SVE hardware instructions via intrinsics + /// + [Intrinsic] + [CLSCompliant(false)] + [Experimental(Experimentals.ArmSveDiagId, UrlFormat = Experimentals.SharedUrlFormat)] + public abstract class Sve2 : Sve + { + internal Sve2() { } + + public static new bool IsSupported { get => IsSupported; } + + [Intrinsic] + public new abstract class Arm64 : Sve.Arm64 + { + internal Arm64() { } + + public static new bool IsSupported { get => IsSupported; } + } + + // Bitwise clear and exclusive OR + + /// + /// svuint8_t svbcax[_u8](svuint8_t op1, svuint8_t op2, svuint8_t op3) + /// BCAX Ztied1.D, Ztied1.D, Zop2.D, Zop3.D + /// + public static unsafe Vector BitwiseClearXor(Vector xor, Vector value, Vector mask) => BitwiseClearXor(xor, value, mask); + + /// + /// svint16_t svbcax[_s16](svint16_t op1, svint16_t op2, svint16_t op3) + /// BCAX Ztied1.D, Ztied1.D, Zop2.D, Zop3.D + /// + public static unsafe Vector BitwiseClearXor(Vector xor, Vector value, Vector mask) => BitwiseClearXor(xor, value, mask); + + /// + /// svint32_t svbcax[_s32](svint32_t op1, svint32_t op2, svint32_t op3) + /// BCAX Ztied1.D, Ztied1.D, Zop2.D, Zop3.D + /// + public static unsafe Vector BitwiseClearXor(Vector xor, Vector value, Vector mask) => BitwiseClearXor(xor, value, mask); + + /// + /// svint64_t svbcax[_s64](svint64_t op1, svint64_t op2, svint64_t op3) + /// BCAX Ztied1.D, Ztied1.D, Zop2.D, Zop3.D + /// + public static unsafe Vector BitwiseClearXor(Vector xor, Vector value, Vector mask) => BitwiseClearXor(xor, value, mask); + + /// + /// svint8_t svbcax[_s8](svint8_t op1, svint8_t op2, svint8_t op3) + /// BCAX Ztied1.D, Ztied1.D, Zop2.D, Zop3.D + /// + public static unsafe Vector BitwiseClearXor(Vector xor, Vector value, Vector mask) => BitwiseClearXor(xor, value, mask); + + /// + /// svuint16_t svbcax[_u16](svuint16_t op1, svuint16_t op2, svuint16_t op3) + /// BCAX Ztied1.D, Ztied1.D, Zop2.D, Zop3.D + /// + public static unsafe Vector BitwiseClearXor(Vector xor, Vector value, Vector mask) => BitwiseClearXor(xor, value, mask); + + /// + /// svuint32_t svbcax[_u32](svuint32_t op1, svuint32_t op2, svuint32_t op3) + /// BCAX Ztied1.D, Ztied1.D, Zop2.D, Zop3.D + /// + public static unsafe Vector BitwiseClearXor(Vector xor, Vector value, Vector mask) => BitwiseClearXor(xor, value, mask); + + /// + /// svuint64_t svbcax[_u64](svuint64_t op1, svuint64_t op2, svuint64_t op3) + /// BCAX Ztied1.D, Ztied1.D, Zop2.D, Zop3.D + /// + public static unsafe Vector BitwiseClearXor(Vector xor, Vector value, Vector mask) => BitwiseClearXor(xor, value, mask); + } +} diff --git a/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs b/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs index 02984d153ab9fd..6aee8d00d4af9b 100644 --- a/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs +++ b/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs @@ -5971,6 +5971,28 @@ internal Arm64() { } public static System.Numerics.Vector ZipLow(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } } + [System.CLSCompliantAttribute(false)] + [System.Diagnostics.CodeAnalysis.ExperimentalAttribute("SYSLIB5003", UrlFormat = "https://aka.ms/dotnet-warnings/{0}")] + public abstract partial class Sve2 : System.Runtime.Intrinsics.Arm.Sve + { + internal Sve2() { } + public static new bool IsSupported { get { throw null; } } + public new abstract partial class Arm64 : System.Runtime.Intrinsics.Arm.Sve.Arm64 + { + internal Arm64() { } + public static new bool IsSupported { get { throw null; } } + } + + public static System.Numerics.Vector BitwiseClearXor(System.Numerics.Vector xor, System.Numerics.Vector value, System.Numerics.Vector mask) { throw null; } + public static System.Numerics.Vector BitwiseClearXor(System.Numerics.Vector xor, System.Numerics.Vector value, System.Numerics.Vector mask) { throw null; } + public static System.Numerics.Vector BitwiseClearXor(System.Numerics.Vector xor, System.Numerics.Vector value, System.Numerics.Vector mask) { throw null; } + public static System.Numerics.Vector BitwiseClearXor(System.Numerics.Vector xor, System.Numerics.Vector value, System.Numerics.Vector mask) { throw null; } + public static System.Numerics.Vector BitwiseClearXor(System.Numerics.Vector xor, System.Numerics.Vector value, System.Numerics.Vector mask) { throw null; } + public static System.Numerics.Vector BitwiseClearXor(System.Numerics.Vector xor, System.Numerics.Vector value, System.Numerics.Vector mask) { throw null; } + public static System.Numerics.Vector BitwiseClearXor(System.Numerics.Vector xor, System.Numerics.Vector value, System.Numerics.Vector mask) { throw null; } + public static System.Numerics.Vector BitwiseClearXor(System.Numerics.Vector xor, System.Numerics.Vector value, System.Numerics.Vector mask) { throw null; } + } + public enum SveMaskPattern : byte { LargestPowerOf2 = 0, // The largest power of 2. diff --git a/src/tests/Common/GenerateHWIntrinsicTests/GenerateHWIntrinsicTests_Arm.cs b/src/tests/Common/GenerateHWIntrinsicTests/GenerateHWIntrinsicTests_Arm.cs index e8f4ba96d7d16f..440e9ee20e3bb1 100644 --- a/src/tests/Common/GenerateHWIntrinsicTests/GenerateHWIntrinsicTests_Arm.cs +++ b/src/tests/Common/GenerateHWIntrinsicTests/GenerateHWIntrinsicTests_Arm.cs @@ -4738,6 +4738,17 @@ ("SveVecPairBinOpTest.template", new Dictionary { ["TestName"] = "Sve_TransposeOdd_ulong", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "TransposeOdd", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["ValidateEntry"] = "result[i] != left[index * 2 + 1] || result[i + 1] != right[index * 2 + 1]"}), }; +(string templateFileName, Dictionary templateData)[] Sve2Inputs = new[] +{ + ("SveVecTernOpTest.template", new Dictionary { ["TestName"] = "Sve2_BitwiseClearXor_sbyte", ["Isa"] = "Sve2", ["LoadIsa"] = "Sve2", ["Method"] = "BitwiseClearXor", ["RetVectorType"] = "Vector", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "SByte", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "SByte", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp3"] = "TestLibrary.Generator.GetSByte()", ["ConvertFunc"] = "", ["ValidateIterResult"] = "result[i] != Helpers.BitwiseClearXor(firstOp[i], secondOp[i], thirdOp[i])", ["GetIterResult"] = "Helpers.BitwiseClearXor(firstOp[i], secondOp[i], thirdOp[i])"}), + ("SveVecTernOpTest.template", new Dictionary { ["TestName"] = "Sve2_BitwiseClearXor_short", ["Isa"] = "Sve2", ["LoadIsa"] = "Sve2", ["Method"] = "BitwiseClearXor", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "Int16", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "Int16", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt16()", ["ConvertFunc"] = "", ["ValidateIterResult"] = "result[i] != Helpers.BitwiseClearXor(firstOp[i], secondOp[i], thirdOp[i])", ["GetIterResult"] = "Helpers.BitwiseClearXor(firstOp[i], secondOp[i], thirdOp[i])"}), + ("SveVecTernOpTest.template", new Dictionary { ["TestName"] = "Sve2_BitwiseClearXor_int", ["Isa"] = "Sve2", ["LoadIsa"] = "Sve2", ["Method"] = "BitwiseClearXor", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "Int32", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "Int32", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt32()", ["ConvertFunc"] = "", ["ValidateIterResult"] = "result[i] != Helpers.BitwiseClearXor(firstOp[i], secondOp[i], thirdOp[i])", ["GetIterResult"] = "Helpers.BitwiseClearXor(firstOp[i], secondOp[i], thirdOp[i])"}), + ("SveVecTernOpTest.template", new Dictionary { ["TestName"] = "Sve2_BitwiseClearXor_long", ["Isa"] = "Sve2", ["LoadIsa"] = "Sve2", ["Method"] = "BitwiseClearXor", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "Int64", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "Int64", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt64()", ["ConvertFunc"] = "", ["ValidateIterResult"] = "result[i] != Helpers.BitwiseClearXor(firstOp[i], secondOp[i], thirdOp[i])", ["GetIterResult"] = "Helpers.BitwiseClearXor(firstOp[i], secondOp[i], thirdOp[i])"}), + ("SveVecTernOpTest.template", new Dictionary { ["TestName"] = "Sve2_BitwiseClearXor_byte", ["Isa"] = "Sve2", ["LoadIsa"] = "Sve2", ["Method"] = "BitwiseClearXor", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "Byte", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "Byte", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["NextValueOp3"] = "TestLibrary.Generator.GetByte()", ["ConvertFunc"] = "", ["ValidateIterResult"] = "result[i] != Helpers.BitwiseClearXor(firstOp[i], secondOp[i], thirdOp[i])", ["GetIterResult"] = "Helpers.BitwiseClearXor(firstOp[i], secondOp[i], thirdOp[i])"}), + ("SveVecTernOpTest.template", new Dictionary { ["TestName"] = "Sve2_BitwiseClearXor_ushort", ["Isa"] = "Sve2", ["LoadIsa"] = "Sve2", ["Method"] = "BitwiseClearXor", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "UInt16", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "UInt16", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt16()", ["ConvertFunc"] = "", ["ValidateIterResult"] = "result[i] != Helpers.BitwiseClearXor(firstOp[i], secondOp[i], thirdOp[i])", ["GetIterResult"] = "Helpers.BitwiseClearXor(firstOp[i], secondOp[i], thirdOp[i])"}), + ("SveVecTernOpTest.template", new Dictionary { ["TestName"] = "Sve2_BitwiseClearXor_uint", ["Isa"] = "Sve2", ["LoadIsa"] = "Sve2", ["Method"] = "BitwiseClearXor", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "UInt32", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "UInt32", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt32()", ["ConvertFunc"] = "", ["ValidateIterResult"] = "result[i] != Helpers.BitwiseClearXor(firstOp[i], secondOp[i], thirdOp[i])", ["GetIterResult"] = "Helpers.BitwiseClearXor(firstOp[i], secondOp[i], thirdOp[i])"}), + ("SveVecTernOpTest.template", new Dictionary { ["TestName"] = "Sve2_BitwiseClearXor_ulong", ["Isa"] = "Sve2", ["LoadIsa"] = "Sve2", ["Method"] = "BitwiseClearXor", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "UInt64", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "UInt64", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt64()", ["ConvertFunc"] = "", ["ValidateIterResult"] = "result[i] != Helpers.BitwiseClearXor(firstOp[i], secondOp[i], thirdOp[i])", ["GetIterResult"] = "Helpers.BitwiseClearXor(firstOp[i], secondOp[i], thirdOp[i])"}), +}; string projectName = args[0]; string templateDirectory = args[1]; @@ -4757,6 +4768,7 @@ ProcessInputs("Sha1", Sha1Inputs); ProcessInputs("Sha256", Sha256Inputs); ProcessInputs("Sve", SveInputs); +ProcessInputs("Sve2", Sve2Inputs); void ProcessInputs(string groupName, (string templateFileName, Dictionary templateData)[] inputs) { diff --git a/src/tests/JIT/HardwareIntrinsics/Arm/Shared/Helpers.cs b/src/tests/JIT/HardwareIntrinsics/Arm/Shared/Helpers.cs index ef91904ae2bc40..0eaa30b8440e95 100644 --- a/src/tests/JIT/HardwareIntrinsics/Arm/Shared/Helpers.cs +++ b/src/tests/JIT/HardwareIntrinsics/Arm/Shared/Helpers.cs @@ -9832,5 +9832,10 @@ public static double[] ConditionalExtractLastActiveElementAndReplicate(double[] { return ConditionalExtract(op1, op2, op3, /* after = */ false, /* replicate = */ true); } + + public static T BitwiseClearXor(T op1, T op2, T op3) where T : IBitwiseOperators + { + return op1 ^ (op2 & ~op3); + } } } diff --git a/src/tests/JIT/HardwareIntrinsics/Arm/Shared/Program.cs b/src/tests/JIT/HardwareIntrinsics/Arm/Shared/Program.cs index 4ad42ce51fd0a1..0fbde7611d064f 100644 --- a/src/tests/JIT/HardwareIntrinsics/Arm/Shared/Program.cs +++ b/src/tests/JIT/HardwareIntrinsics/Arm/Shared/Program.cs @@ -22,6 +22,7 @@ public static void PrintSupportedIsa() TestLibrary.TestFramework.LogInformation($" Sha1: {Sha1.IsSupported}"); TestLibrary.TestFramework.LogInformation($" Sha256: {Sha256.IsSupported}"); TestLibrary.TestFramework.LogInformation($" Sve: {Sve.IsSupported}"); + TestLibrary.TestFramework.LogInformation($" Sve2: {Sve2.IsSupported}"); TestLibrary.TestFramework.LogInformation(string.Empty); } } diff --git a/src/tests/JIT/HardwareIntrinsics/Arm/Sve2/Program.Sve2.cs b/src/tests/JIT/HardwareIntrinsics/Arm/Sve2/Program.Sve2.cs new file mode 100644 index 00000000000000..4a3dd74fe88d21 --- /dev/null +++ b/src/tests/JIT/HardwareIntrinsics/Arm/Sve2/Program.Sve2.cs @@ -0,0 +1,16 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; + +namespace JIT.HardwareIntrinsics.Arm._Sve2 +{ + public static partial class Program + { + static Program() + { + JIT.HardwareIntrinsics.Arm.Program.PrintSupportedIsa(); + } + } +} diff --git a/src/tests/JIT/HardwareIntrinsics/Arm/Sve2/Sve2_r.csproj b/src/tests/JIT/HardwareIntrinsics/Arm/Sve2/Sve2_r.csproj new file mode 100644 index 00000000000000..a7c38137553dec --- /dev/null +++ b/src/tests/JIT/HardwareIntrinsics/Arm/Sve2/Sve2_r.csproj @@ -0,0 +1,20 @@ + + + true + + + Embedded + + + + + + + + + + + + + + diff --git a/src/tests/JIT/HardwareIntrinsics/Arm/Sve2/Sve2_ro.csproj b/src/tests/JIT/HardwareIntrinsics/Arm/Sve2/Sve2_ro.csproj new file mode 100644 index 00000000000000..10acace4133a8b --- /dev/null +++ b/src/tests/JIT/HardwareIntrinsics/Arm/Sve2/Sve2_ro.csproj @@ -0,0 +1,20 @@ + + + true + + + Embedded + True + + + + + + + + + + + + + From f133097dccd30c4adc5dc320464fcc496857a593 Mon Sep 17 00:00:00 2001 From: Sebastian Nickolls Date: Mon, 12 May 2025 09:57:43 +0000 Subject: [PATCH 2/2] Add missing movprfx case --- src/coreclr/jit/hwintrinsiccodegenarm64.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/coreclr/jit/hwintrinsiccodegenarm64.cpp b/src/coreclr/jit/hwintrinsiccodegenarm64.cpp index cf1f8cca4447cc..b03b492fa4045e 100644 --- a/src/coreclr/jit/hwintrinsiccodegenarm64.cpp +++ b/src/coreclr/jit/hwintrinsiccodegenarm64.cpp @@ -2650,9 +2650,13 @@ void CodeGen::genHWIntrinsic(GenTreeHWIntrinsic* node) } case NI_Sve2_BitwiseClearXor: - assert(targetReg == op1Reg); + if (targetReg != op1Reg) + { + assert(targetReg != op2Reg); + GetEmitter()->emitInsSve_R_R(INS_sve_movprfx, EA_SCALABLE, targetReg, op1Reg); + } // Always use the lane size D. It's a bitwise operation so this is fine for all integer vector types. - GetEmitter()->emitIns_R_R_R(ins, emitSize, op1Reg, op2Reg, op3Reg, INS_OPTS_SCALABLE_D); + GetEmitter()->emitInsSve_R_R_R(ins, emitSize, targetReg, op2Reg, op3Reg, INS_OPTS_SCALABLE_D); break; default: