From 66dca240d704da4bbbed0336b90b5effd40d94b3 Mon Sep 17 00:00:00 2001 From: Swapnil Gaikwad Date: Wed, 5 Jun 2024 12:32:07 +0100 Subject: [PATCH 1/7] Add support for Sve.DuplicateScalarToVector() --- src/coreclr/jit/hwintrinsicarm64.cpp | 4 + src/coreclr/jit/hwintrinsiccodegenarm64.cpp | 11 + src/coreclr/jit/hwintrinsiclistarm64sve.h | 1 + src/coreclr/jit/lowerarmarch.cpp | 1 + src/coreclr/jit/lsraarm64.cpp | 1 + .../Arm/Sve.PlatformNotSupported.cs | 64 +++ .../src/System/Runtime/Intrinsics/Arm/Sve.cs | 64 +++ .../ref/System.Runtime.Intrinsics.cs | 11 + .../GenerateHWIntrinsicTests_Arm.cs | 12 + .../_SveImmUnaryOpTestTemplate.template | 396 ++++++++++++++++++ 10 files changed, 565 insertions(+) create mode 100644 src/tests/JIT/HardwareIntrinsics/Arm/Shared/_SveImmUnaryOpTestTemplate.template diff --git a/src/coreclr/jit/hwintrinsicarm64.cpp b/src/coreclr/jit/hwintrinsicarm64.cpp index 095f31246d0c68..bdf5d6c0f8e690 100644 --- a/src/coreclr/jit/hwintrinsicarm64.cpp +++ b/src/coreclr/jit/hwintrinsicarm64.cpp @@ -421,6 +421,10 @@ void HWIntrinsicInfo::lookupImmBounds( immUpperBound = (int)SVE_PATTERN_ALL; break; + case NI_Sve_DuplicateSelectedScalarToVector: + immUpperBound = (512 / (genTypeSize(baseType) * BITS_PER_BYTE)) - 1; + break; + case NI_Sve_SaturatingDecrementBy16BitElementCount: case NI_Sve_SaturatingDecrementBy32BitElementCount: case NI_Sve_SaturatingDecrementBy64BitElementCount: diff --git a/src/coreclr/jit/hwintrinsiccodegenarm64.cpp b/src/coreclr/jit/hwintrinsiccodegenarm64.cpp index 23b09c0cef751e..08b89ecbc30c43 100644 --- a/src/coreclr/jit/hwintrinsiccodegenarm64.cpp +++ b/src/coreclr/jit/hwintrinsiccodegenarm64.cpp @@ -784,6 +784,17 @@ void CodeGen::genHWIntrinsic(GenTreeHWIntrinsic* node) unreached(); } } + else if (intrin.id == NI_Sve_DuplicateSelectedScalarToVector) + { + HWIntrinsicImmOpHelper helper(this, intrin.op2, node); + + for (helper.EmitBegin(); !helper.Done(); helper.EmitCaseEnd()) + { + const int elementIndex = helper.ImmValue(); + + GetEmitter()->emitIns_R_R_I(ins, emitSize, targetReg, op1Reg, elementIndex, opt); + } + } else { assert(!hasImmediateOperand); diff --git a/src/coreclr/jit/hwintrinsiclistarm64sve.h b/src/coreclr/jit/hwintrinsiclistarm64sve.h index e047fc64447c14..0f0647137edd49 100644 --- a/src/coreclr/jit/hwintrinsiclistarm64sve.h +++ b/src/coreclr/jit/hwintrinsiclistarm64sve.h @@ -67,6 +67,7 @@ HARDWARE_INTRINSIC(Sve, CreateWhileLessThanOrEqualMask8Bit, HARDWARE_INTRINSIC(Sve, Divide, -1, 2, true, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_sdiv, INS_sve_udiv, INS_sve_sdiv, INS_sve_udiv, INS_sve_fdiv, INS_sve_fdiv}, HW_Category_SIMD, HW_Flag_Scalable|HW_Flag_EmbeddedMaskedOperation|HW_Flag_HasRMWSemantics|HW_Flag_LowMaskedOperation) HARDWARE_INTRINSIC(Sve, DotProduct, -1, 3, true, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_sdot, INS_sve_udot, INS_sve_sdot, INS_sve_udot, INS_invalid, INS_invalid}, HW_Category_SIMD, HW_Flag_Scalable|HW_Flag_HasRMWSemantics) HARDWARE_INTRINSIC(Sve, DotProductBySelectedScalar, -1, 4, true, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_sdot, INS_sve_udot, INS_sve_sdot, INS_sve_udot, INS_invalid, INS_invalid}, HW_Category_SIMDByIndexedElement, HW_Flag_Scalable|HW_Flag_BaseTypeFromFirstArg|HW_Flag_HasImmediateOperand|HW_Flag_HasRMWSemantics|HW_Flag_LowVectorOperation) +HARDWARE_INTRINSIC(Sve, DuplicateSelectedScalarToVector, -1, 2, true, {INS_sve_dup, INS_sve_dup, INS_sve_dup, INS_sve_dup, INS_sve_dup, INS_sve_dup, INS_sve_dup, INS_sve_dup, INS_sve_dup, INS_sve_dup}, HW_Category_SIMD, HW_Flag_Scalable|HW_Flag_HasImmediateOperand) HARDWARE_INTRINSIC(Sve, FusedMultiplyAdd, -1, -1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_fmla, INS_sve_fmla}, HW_Category_SIMD, HW_Flag_Scalable|HW_Flag_EmbeddedMaskedOperation|HW_Flag_HasRMWSemantics|HW_Flag_LowMaskedOperation|HW_Flag_FmaIntrinsic|HW_Flag_SpecialCodeGen) HARDWARE_INTRINSIC(Sve, FusedMultiplyAddBySelectedScalar, -1, 4, true, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_fmla, INS_sve_fmla}, HW_Category_SIMDByIndexedElement, HW_Flag_Scalable|HW_Flag_HasImmediateOperand|HW_Flag_HasRMWSemantics|HW_Flag_FmaIntrinsic|HW_Flag_LowVectorOperation) HARDWARE_INTRINSIC(Sve, FusedMultiplyAddNegated, -1, -1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_fnmla, INS_sve_fnmla}, HW_Category_SIMD, HW_Flag_Scalable|HW_Flag_EmbeddedMaskedOperation|HW_Flag_HasRMWSemantics|HW_Flag_LowMaskedOperation|HW_Flag_FmaIntrinsic|HW_Flag_SpecialCodeGen) diff --git a/src/coreclr/jit/lowerarmarch.cpp b/src/coreclr/jit/lowerarmarch.cpp index cebda711b24f6b..16ef0407d9e6fb 100644 --- a/src/coreclr/jit/lowerarmarch.cpp +++ b/src/coreclr/jit/lowerarmarch.cpp @@ -3176,6 +3176,7 @@ void Lowering::ContainCheckHWIntrinsic(GenTreeHWIntrinsic* node) case NI_AdvSimd_Arm64_LoadAndInsertScalarVector128x3: case NI_AdvSimd_Arm64_LoadAndInsertScalarVector128x4: case NI_AdvSimd_Arm64_DuplicateSelectedScalarToVector128: + case NI_Sve_DuplicateSelectedScalarToVector: assert(hasImmediateOperand); assert(varTypeIsIntegral(intrin.op2)); if (intrin.op2->IsCnsIntOrI()) diff --git a/src/coreclr/jit/lsraarm64.cpp b/src/coreclr/jit/lsraarm64.cpp index 53c543291671ec..4bc0f6ef3f11a6 100644 --- a/src/coreclr/jit/lsraarm64.cpp +++ b/src/coreclr/jit/lsraarm64.cpp @@ -1434,6 +1434,7 @@ int LinearScan::BuildHWIntrinsic(GenTreeHWIntrinsic* intrinsicTree, int* pDstCou case NI_AdvSimd_Arm64_LoadAndInsertScalarVector128x3: case NI_AdvSimd_Arm64_LoadAndInsertScalarVector128x4: case NI_AdvSimd_Arm64_DuplicateSelectedScalarToVector128: + case NI_Sve_DuplicateSelectedScalarToVector: needBranchTargetReg = !intrin.op2->isContainedIntOrIImmed(); break; diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/Sve.PlatformNotSupported.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/Sve.PlatformNotSupported.cs index bbce99bcf03716..d369d01a511626 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/Sve.PlatformNotSupported.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/Sve.PlatformNotSupported.cs @@ -1360,6 +1360,70 @@ internal Arm64() { } /// public static unsafe Vector DotProductBySelectedScalar(Vector addend, Vector left, Vector right, [ConstantExpected] byte rightIndex) { throw new PlatformNotSupportedException(); } + + /// Broadcast a scalar value + + /// + /// svuint8_t svdup_lane[_u8](svuint8_t data, uint8_t index) + /// DUP Zresult.B, Zdata.B[index] + /// + public static unsafe Vector DuplicateSelectedScalarToVector(Vector data, [ConstantExpected] byte index) { throw new PlatformNotSupportedException(); } + + /// + /// svfloat64_t svdup_lane[_f64](svfloat64_t data, uint64_t index) + /// DUP Zresult.D, Zdata.D[index] + /// + public static unsafe Vector DuplicateSelectedScalarToVector(Vector data, [ConstantExpected] byte index) { throw new PlatformNotSupportedException(); } + + /// + /// svint16_t svdup_lane[_s16](svint16_t data, uint16_t index) + /// DUP Zresult.H, Zdata.H[index] + /// + public static unsafe Vector DuplicateSelectedScalarToVector(Vector data, [ConstantExpected] byte index) { throw new PlatformNotSupportedException(); } + + /// + /// svint32_t svdup_lane[_s32](svint32_t data, uint32_t index) + /// DUP Zresult.S, Zdata.S[index] + /// + public static unsafe Vector DuplicateSelectedScalarToVector(Vector data, [ConstantExpected] byte index) { throw new PlatformNotSupportedException(); } + + /// + /// svint64_t svdup_lane[_s64](svint64_t data, uint64_t index) + /// DUP Zresult.D, Zdata.D[index] + /// + public static unsafe Vector DuplicateSelectedScalarToVector(Vector data, [ConstantExpected] byte index) { throw new PlatformNotSupportedException(); } + + /// + /// svint8_t svdup_lane[_s8](svint8_t data, uint8_t index) + /// DUP Zresult.B, Zdata.B[index] + /// + public static unsafe Vector DuplicateSelectedScalarToVector(Vector data, [ConstantExpected] byte index) { throw new PlatformNotSupportedException(); } + + /// + /// svfloat32_t svdup_lane[_f32](svfloat32_t data, uint32_t index) + /// DUP Zresult.S, Zdata.S[index] + /// + public static unsafe Vector DuplicateSelectedScalarToVector(Vector data, [ConstantExpected] byte index) { throw new PlatformNotSupportedException(); } + + /// + /// svuint16_t svdup_lane[_u16](svuint16_t data, uint16_t index) + /// DUP Zresult.H, Zdata.H[index] + /// + public static unsafe Vector DuplicateSelectedScalarToVector(Vector data, [ConstantExpected] byte index) { throw new PlatformNotSupportedException(); } + + /// + /// svuint32_t svdup_lane[_u32](svuint32_t data, uint32_t index) + /// DUP Zresult.S, Zdata.S[index] + /// + public static unsafe Vector DuplicateSelectedScalarToVector(Vector data, [ConstantExpected] byte index) { throw new PlatformNotSupportedException(); } + + /// + /// svuint64_t svdup_lane[_u64](svuint64_t data, uint64_t index) + /// DUP Zresult.D, Zdata.D[index] + /// + public static unsafe Vector DuplicateSelectedScalarToVector(Vector data, [ConstantExpected] byte index) { throw new PlatformNotSupportedException(); } + + /// FusedMultiplyAdd : Multiply-add, addend first /// diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/Sve.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/Sve.cs index 8295f37ba40833..067dca04df9921 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/Sve.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/Sve.cs @@ -1416,6 +1416,70 @@ internal Arm64() { } /// public static unsafe Vector DotProductBySelectedScalar(Vector addend, Vector left, Vector right, [ConstantExpected] byte rightIndex) => DotProductBySelectedScalar(addend, left, right, rightIndex); + + /// Broadcast a scalar value + + /// + /// svuint8_t svdup_lane[_u8](svuint8_t data, uint8_t index) + /// DUP Zresult.B, Zdata.B[index] + /// + public static unsafe Vector DuplicateSelectedScalarToVector(Vector data, [ConstantExpected(Min = 0, Max = (byte)(63))] byte index) => DuplicateSelectedScalarToVector(data, index); + + /// + /// svfloat64_t svdup_lane[_f64](svfloat64_t data, uint64_t index) + /// DUP Zresult.D, Zdata.D[index] + /// + public static unsafe Vector DuplicateSelectedScalarToVector(Vector data, [ConstantExpected(Min = 0, Max = (byte)(7))] byte index) => DuplicateSelectedScalarToVector(data, index); + + /// + /// svint16_t svdup_lane[_s16](svint16_t data, uint16_t index) + /// DUP Zresult.H, Zdata.H[index] + /// + public static unsafe Vector DuplicateSelectedScalarToVector(Vector data, [ConstantExpected(Min = 0, Max = (byte)(31))] byte index) => DuplicateSelectedScalarToVector(data, index); + + /// + /// svint32_t svdup_lane[_s32](svint32_t data, uint32_t index) + /// DUP Zresult.S, Zdata.S[index] + /// + public static unsafe Vector DuplicateSelectedScalarToVector(Vector data, [ConstantExpected(Min = 0, Max = (byte)(15))] byte index) => DuplicateSelectedScalarToVector(data, index); + + /// + /// svint64_t svdup_lane[_s64](svint64_t data, uint64_t index) + /// DUP Zresult.D, Zdata.D[index] + /// + public static unsafe Vector DuplicateSelectedScalarToVector(Vector data, [ConstantExpected(Min = 0, Max = (byte)(7))] byte index) => DuplicateSelectedScalarToVector(data, index); + + /// + /// svint8_t svdup_lane[_s8](svint8_t data, uint8_t index) + /// DUP Zresult.B, Zdata.B[index] + /// + public static unsafe Vector DuplicateSelectedScalarToVector(Vector data, [ConstantExpected(Min = 0, Max = (byte)(63))] byte index) => DuplicateSelectedScalarToVector(data, index); + + /// + /// svfloat32_t svdup_lane[_f32](svfloat32_t data, uint32_t index) + /// DUP Zresult.S, Zdata.S[index] + /// + public static unsafe Vector DuplicateSelectedScalarToVector(Vector data, [ConstantExpected(Min = 0, Max = (byte)(15))] byte index) => DuplicateSelectedScalarToVector(data, index); + + /// + /// svuint16_t svdup_lane[_u16](svuint16_t data, uint16_t index) + /// DUP Zresult.H, Zdata.H[index] + /// + public static unsafe Vector DuplicateSelectedScalarToVector(Vector data, [ConstantExpected(Min = 0, Max = (byte)(31))] byte index) => DuplicateSelectedScalarToVector(data, index); + + /// + /// svuint32_t svdup_lane[_u32](svuint32_t data, uint32_t index) + /// DUP Zresult.S, Zdata.S[index] + /// + public static unsafe Vector DuplicateSelectedScalarToVector(Vector data, [ConstantExpected(Min = 0, Max = (byte)(15))] byte index) => DuplicateSelectedScalarToVector(data, index); + + /// + /// svuint64_t svdup_lane[_u64](svuint64_t data, uint64_t index) + /// DUP Zresult.D, Zdata.D[index] + /// + public static unsafe Vector DuplicateSelectedScalarToVector(Vector data, [ConstantExpected(Min = 0, Max = (byte)(7))] byte index) => DuplicateSelectedScalarToVector(data, index); + + /// FusedMultiplyAdd : Multiply-add, addend first /// 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 b5d78df0f8b8d4..31a82e71bee6e1 100644 --- a/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs +++ b/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs @@ -4378,6 +4378,17 @@ internal Arm64() { } public static System.Numerics.Vector DotProductBySelectedScalar(System.Numerics.Vector addend, System.Numerics.Vector left, System.Numerics.Vector right, [ConstantExpected] byte rightIndex) { throw null; } public static System.Numerics.Vector DotProductBySelectedScalar(System.Numerics.Vector addend, System.Numerics.Vector left, System.Numerics.Vector right, [ConstantExpected] byte rightIndex) { throw null; } + public static System.Numerics.Vector DuplicateSelectedScalarToVector(System.Numerics.Vector data, [ConstantExpected] byte index) { throw null; } + public static System.Numerics.Vector DuplicateSelectedScalarToVector(System.Numerics.Vector data, [ConstantExpected] byte index) { throw null; } + public static System.Numerics.Vector DuplicateSelectedScalarToVector(System.Numerics.Vector data, [ConstantExpected] byte index) { throw null; } + public static System.Numerics.Vector DuplicateSelectedScalarToVector(System.Numerics.Vector data, [ConstantExpected] byte index) { throw null; } + public static System.Numerics.Vector DuplicateSelectedScalarToVector(System.Numerics.Vector data, [ConstantExpected] byte index) { throw null; } + public static System.Numerics.Vector DuplicateSelectedScalarToVector(System.Numerics.Vector data, [ConstantExpected] byte index) { throw null; } + public static System.Numerics.Vector DuplicateSelectedScalarToVector(System.Numerics.Vector data, [ConstantExpected] byte index) { throw null; } + public static System.Numerics.Vector DuplicateSelectedScalarToVector(System.Numerics.Vector data, [ConstantExpected] byte index) { throw null; } + public static System.Numerics.Vector DuplicateSelectedScalarToVector(System.Numerics.Vector data, [ConstantExpected] byte index) { throw null; } + public static System.Numerics.Vector DuplicateSelectedScalarToVector(System.Numerics.Vector data, [ConstantExpected] byte index) { throw null; } + public static System.Numerics.Vector FusedMultiplyAdd(System.Numerics.Vector addend, System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } public static System.Numerics.Vector FusedMultiplyAdd(System.Numerics.Vector addend, System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } public static System.Numerics.Vector FusedMultiplyAddBySelectedScalar(System.Numerics.Vector addend, System.Numerics.Vector left, System.Numerics.Vector right, [ConstantExpected] byte rightIndex) { throw null; } diff --git a/src/tests/Common/GenerateHWIntrinsicTests/GenerateHWIntrinsicTests_Arm.cs b/src/tests/Common/GenerateHWIntrinsicTests/GenerateHWIntrinsicTests_Arm.cs index e1a3d2294618db..efadbafe6dddaf 100644 --- a/src/tests/Common/GenerateHWIntrinsicTests/GenerateHWIntrinsicTests_Arm.cs +++ b/src/tests/Common/GenerateHWIntrinsicTests/GenerateHWIntrinsicTests_Arm.cs @@ -172,6 +172,7 @@ ("_SveBinaryOpTestTemplate.template", "SveVecBinOpConvertTest.template",new Dictionary { ["TemplateName"] = "Simple", ["TemplateValidationLogic"] = SimpleVecOpTest_ValidationLogic, ["TemplateValidationLogicForCndSel"] = SimpleTernVecOpTest_ValidationLogicForCndSel }), ("_SveBinaryMaskOpTestTemplate.template", "SveMaskVecBinOpConvertTest.template",new Dictionary { ["TemplateName"] = "Simple", ["TemplateValidationLogic"] = SimpleVecOpTest_ValidationLogic, ["TemplateValidationLogicForCndSel"] = SimpleVecOpTest_ValidationLogicForCndSel }), ("_SveImmBinaryOpTestTemplate.template", "SveVecImmBinOpTest.template", new Dictionary { ["TemplateName"] = "Simple", ["TemplateValidationLogic"] = SimpleVecOpTest_ValidationLogic, ["TemplateValidationLogicForCndSel"] = SimpleVecOpTest_ValidationLogicForCndSel }), + ("_SveImmUnaryOpTestTemplate.template", "SveVecImmUnOpTest.template", new Dictionary { ["TemplateName"] = "Simple", ["TemplateValidationLogic"] = SimpleVecOpTest_ValidationLogic, ["TemplateValidationLogicForCndSel"] = SimpleVecOpTest_ValidationLogicForCndSel }), ("_SveTernOpTestTemplate.template", "SveVecTernOpTest.template", new Dictionary { ["TemplateName"] = "Simple", ["TemplateValidationLogic"] = SimpleVecOpTest_ValidationLogic, ["TemplateValidationLogicForCndSel"] = SimpleTernVecOpTest_ValidationLogicForCndSel }), ("_SveTernOpFirstArgTestTemplate.template", "SveVecTernOpFirstArgTest.template", new Dictionary { ["TemplateName"] = "Simple", ["TemplateValidationLogic"] = SimpleVecOpTest_ValidationLogic, ["TemplateValidationLogicForCndSel"] = SimpleTernVecOpTest_ValidationLogicForCndSel }), ("_SveImmTernOpTestTemplate.template", "SveVecImmTernOpTest.template", new Dictionary { ["TemplateName"] = "Simple", ["TemplateValidationLogic"] = SimpleVecOpTest_ValidationLogic, ["TemplateValidationLogicForCndSel"] = SimpleTernVecOpTest_ValidationLogicForCndSel }), @@ -3724,6 +3725,17 @@ ("SveVecPairBinOpTest.template", new Dictionary { ["TestName"] = "SveTransposeOdd_ushort", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "TransposeOdd", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateEntry"] = "result[i] != left[index * 2 + 1] || result[i + 1] != right[index * 2 + 1]"}), ("SveVecPairBinOpTest.template", new Dictionary { ["TestName"] = "SveTransposeOdd_uint", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "TransposeOdd", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateEntry"] = "result[i] != left[index * 2 + 1] || result[i + 1] != right[index * 2 + 1]"}), ("SveVecPairBinOpTest.template", new Dictionary { ["TestName"] = "SveTransposeOdd_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]"}), + + ("SveVecImmUnOpTest.template", new Dictionary { ["TestName"] = "SveDuplicateSelectedScalarToVector_float", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "DuplicateSelectedScalarToVector", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Single", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["InvalidImm"] = "15", ["Imm"] = "0", ["ValidateIterResult"] = "result[i] != (testValid ? firstOp[Imm] : 0)", ["GetIterResult"] = "firstOp[Imm]"}), + ("SveVecImmUnOpTest.template", new Dictionary { ["TestName"] = "SveDuplicateSelectedScalarToVector_double", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "DuplicateSelectedScalarToVector", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Double", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["InvalidImm"] = "7", ["Imm"] = "0", ["ValidateIterResult"] = "result[i] != (testValid ? firstOp[Imm] : 0)", ["GetIterResult"] = "firstOp[Imm]"}), + ("SveVecImmUnOpTest.template", new Dictionary { ["TestName"] = "SveDuplicateSelectedScalarToVector_sbyte", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "DuplicateSelectedScalarToVector", ["RetVectorType"] = "Vector", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "SByte", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["InvalidImm"] = "63", ["Imm"] = "0", ["ValidateIterResult"] = "result[i] != (testValid ? firstOp[Imm] : 0)", ["GetIterResult"] = "firstOp[Imm]"}), + ("SveVecImmUnOpTest.template", new Dictionary { ["TestName"] = "SveDuplicateSelectedScalarToVector_short", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "DuplicateSelectedScalarToVector", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int16", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["InvalidImm"] = "31", ["Imm"] = "0", ["ValidateIterResult"] = "result[i] != (testValid ? firstOp[Imm] : 0)", ["GetIterResult"] = "firstOp[Imm]"}), + ("SveVecImmUnOpTest.template", new Dictionary { ["TestName"] = "SveDuplicateSelectedScalarToVector_int", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "DuplicateSelectedScalarToVector", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int32", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["InvalidImm"] = "15", ["Imm"] = "0", ["ValidateIterResult"] = "result[i] != (testValid ? firstOp[Imm] : 0)", ["GetIterResult"] = "firstOp[Imm]"}), + ("SveVecImmUnOpTest.template", new Dictionary { ["TestName"] = "SveDuplicateSelectedScalarToVector_long", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "DuplicateSelectedScalarToVector", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int64", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["InvalidImm"] = "7", ["Imm"] = "0", ["ValidateIterResult"] = "result[i] != (testValid ? firstOp[Imm] : 0)", ["GetIterResult"] = "firstOp[Imm]"}), + ("SveVecImmUnOpTest.template", new Dictionary { ["TestName"] = "SveDuplicateSelectedScalarToVector_byte", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "DuplicateSelectedScalarToVector", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Byte", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["InvalidImm"] = "63", ["Imm"] = "0", ["ValidateIterResult"] = "result[i] != (testValid ? firstOp[Imm] : 0)", ["GetIterResult"] = "firstOp[Imm]"}), + ("SveVecImmUnOpTest.template", new Dictionary { ["TestName"] = "SveDuplicateSelectedScalarToVector_ushort", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "DuplicateSelectedScalarToVector", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt16", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["InvalidImm"] = "31", ["Imm"] = "0", ["ValidateIterResult"] = "result[i] != (testValid ? firstOp[Imm] : 0)", ["GetIterResult"] = "firstOp[Imm]"}), + ("SveVecImmUnOpTest.template", new Dictionary { ["TestName"] = "SveDuplicateSelectedScalarToVector_uint", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "DuplicateSelectedScalarToVector", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt32", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["InvalidImm"] = "15", ["Imm"] = "0", ["ValidateIterResult"] = "result[i] != (testValid ? firstOp[Imm] : 0)", ["GetIterResult"] = "firstOp[Imm]"}), + ("SveVecImmUnOpTest.template", new Dictionary { ["TestName"] = "SveDuplicateSelectedScalarToVector_ulong", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "DuplicateSelectedScalarToVector", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt64", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["InvalidImm"] = "7", ["Imm"] = "0", ["ValidateIterResult"] = "result[i] != (testValid ? firstOp[Imm] : 0)", ["GetIterResult"] = "firstOp[Imm]"}), }; diff --git a/src/tests/JIT/HardwareIntrinsics/Arm/Shared/_SveImmUnaryOpTestTemplate.template b/src/tests/JIT/HardwareIntrinsics/Arm/Shared/_SveImmUnaryOpTestTemplate.template new file mode 100644 index 00000000000000..b280d260ba2790 --- /dev/null +++ b/src/tests/JIT/HardwareIntrinsics/Arm/Shared/_SveImmUnaryOpTestTemplate.template @@ -0,0 +1,396 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; +using Xunit; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + [Fact] + public static void {TestName}() + { + var test = new {TemplateName}UnaryOpTest__{TestName}(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if ({LoadIsa}.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + // Validates executing the test inside conditional, with op1 as falseValue + test.ConditionalSelect_Op1(); + // Validates executing the test inside conditional, with op3 as falseValue + test.ConditionalSelect_FalseOp(); + // Validates executing the test inside conditional, with op3 as zero + test.ConditionalSelect_ZeroOp(); + + // Validates basic functionality fails with an invalid imm, using Unsafe.ReadUnaligned + test.RunBasicScenario_UnsafeRead_InvalidImm(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class {TemplateName}UnaryOpTest__{TestName} + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable({Op1BaseType}[] inArray, {RetBaseType}[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf<{Op1BaseType}>(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf<{RetBaseType}>(); + if ((alignment != 64 && alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As<{Op1BaseType}, byte>(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public {Op1VectorType}<{Op1BaseType}> _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = {NextValueOp1}; } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{Op1VectorType}<{Op1BaseType}>, byte>(ref testStruct._fld), ref Unsafe.As<{Op1BaseType}, byte>(ref _data[0]), (uint)Unsafe.SizeOf<{Op1VectorType}<{Op1BaseType}>>()); + + return testStruct; + } + + public void RunStructFldScenario({TemplateName}UnaryOpTest__{TestName} testClass) + { + var result = {Isa}.{Method}(_fld, {Imm}); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, {Imm}, testClass._dataTable.outArrayPtr); + } + } + + private static readonly int LargestVectorSize = {LargestVectorSize}; + + private static readonly int Op1ElementCount = Unsafe.SizeOf<{Op1VectorType}<{Op1BaseType}>>() / sizeof({Op1BaseType}); + private static readonly int RetElementCount = Unsafe.SizeOf<{RetVectorType}<{RetBaseType}>>() / sizeof({RetBaseType}); + private static readonly byte Imm = {Imm}; + + private static {Op1BaseType}[] _maskData = new {Op1BaseType}[Op1ElementCount]; + private static {Op1BaseType}[] _data = new {Op1BaseType}[Op1ElementCount]; + + private {Op1VectorType}<{Op1BaseType}> _mask; + private {Op1VectorType}<{Op1BaseType}> _fld; + private {Op1VectorType}<{Op1BaseType}> _falseFld; + + private DataTable _dataTable; + + public {TemplateName}UnaryOpTest__{TestName}() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _maskData[i] = ({Op1BaseType})({NextValueOp1} % 2); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{Op1VectorType}<{Op1BaseType}>, byte>(ref _mask), ref Unsafe.As<{Op1BaseType}, byte>(ref _maskData[0]), (uint)Unsafe.SizeOf<{Op1VectorType}<{Op1BaseType}>>()); + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = {NextValueOp1}; } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{Op1VectorType}<{Op1BaseType}>, byte>(ref _fld), ref Unsafe.As<{Op1BaseType}, byte>(ref _data[0]), (uint)Unsafe.SizeOf<{Op1VectorType}<{Op1BaseType}>>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = {NextValueOp1}; } + _dataTable = new DataTable(_data, new {RetBaseType}[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => {Isa}.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = {Isa}.{Method}( + Unsafe.Read<{Op1VectorType}<{Op1BaseType}>>(_dataTable.inArrayPtr), + {Imm} + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, {Imm}, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_UnsafeRead_InvalidImm() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead_InvalidImm)); + + var result = {Isa}.{Method}( + Unsafe.Read<{Op1VectorType}<{Op1BaseType}>>(_dataTable.inArrayPtr), + {InvalidImm} + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, {InvalidImm}, _dataTable.outArrayPtr, false); + } + + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + {Op1VectorType}<{Op1BaseType}> loadMask = Sve.CreateTrueMask{RetBaseType}(SveMaskPattern.All); + + var result = {Isa}.{Method}( + {LoadIsa}.Load{Op1VectorType}(loadMask, ({Op1BaseType}*)(_dataTable.inArrayPtr)), + {Imm} + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, {Imm}, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof({Isa}).GetMethod(nameof({Isa}.{Method}), new Type[] { typeof({Op1VectorType}<{Op1BaseType}>), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read<{Op1VectorType}<{Op1BaseType}>>(_dataTable.inArrayPtr), + (byte){Imm} + }); + + Unsafe.Write(_dataTable.outArrayPtr, ({RetVectorType}<{RetBaseType}>)(result)); + ValidateResult(_dataTable.inArrayPtr, {Imm}, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op = Unsafe.Read<{Op1VectorType}<{Op1BaseType}>>(_dataTable.inArrayPtr); + var result = {Isa}.{Method}(op, {Imm}); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op, {Imm}, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = {Isa}.{Method}(_fld, {Imm}); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, {Imm}, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = {Isa}.{Method}(test._fld, {Imm}); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, {Imm}, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void ConditionalSelect_Op1() + { + TestLibrary.TestFramework.BeginScenario("ConditionalSelect_Op1_mask"); + ConditionalSelectScenario(_mask, _fld, _fld); + TestLibrary.TestFramework.BeginScenario("ConditionalSelect_Op1_zero"); + ConditionalSelectScenario({Op1VectorType}<{Op1BaseType}>.Zero, _fld, _fld); + TestLibrary.TestFramework.BeginScenario("ConditionalSelect_Op1_all"); + ConditionalSelectScenario({Op1VectorType}<{Op1BaseType}>.AllBitsSet, _fld, _fld); + } + + public void ConditionalSelect_FalseOp() + { + TestLibrary.TestFramework.BeginScenario("ConditionalSelect_FalseOp_mask"); + ConditionalSelectScenario(_mask, _fld, _falseFld); + TestLibrary.TestFramework.BeginScenario("ConditionalSelect_FalseOp_zero"); + ConditionalSelectScenario({Op1VectorType}<{Op1BaseType}>.Zero, _fld, _falseFld); + TestLibrary.TestFramework.BeginScenario("ConditionalSelect_FalseOp_all"); + ConditionalSelectScenario({Op1VectorType}<{Op1BaseType}>.AllBitsSet, _fld, _falseFld); + } + + public void ConditionalSelect_ZeroOp() + { + TestLibrary.TestFramework.BeginScenario("ConditionalSelect_ZeroOp_mask"); + ConditionalSelectScenario(_mask, _fld, {Op1VectorType}<{Op1BaseType}>.Zero); + TestLibrary.TestFramework.BeginScenario("ConditionalSelect_ZeroOp_zero"); + ConditionalSelectScenario({Op1VectorType}<{Op1BaseType}>.Zero, _fld, {Op1VectorType}<{Op1BaseType}>.Zero); + TestLibrary.TestFramework.BeginScenario("ConditionalSelect_ZeroOp_all"); + ConditionalSelectScenario({Op1VectorType}<{Op1BaseType}>.AllBitsSet, _fld, {Op1VectorType}<{Op1BaseType}>.Zero); + } + + [method: MethodImpl(MethodImplOptions.AggressiveInlining)] + private void ConditionalSelectScenario({Op1VectorType}<{Op1BaseType}> mask, {Op1VectorType}<{Op1BaseType}> op, {Op1VectorType}<{Op1BaseType}> falseOp) + { + var result = Sve.ConditionalSelect(mask, {Isa}.{Method}(op, {Imm}), falseOp); + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateConditionalSelectResult(mask, op, falseOp, {Imm}, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + private void ValidateConditionalSelectResult({Op1VectorType}<{Op1BaseType}> maskOp, {Op1VectorType}<{Op1BaseType}> firstOp, {Op1VectorType}<{Op1BaseType}> falseOp, byte imm, void* output, [CallerMemberName] string method = "") + { + {Op1BaseType}[] mask = new {Op1BaseType}[Op1ElementCount]; + {Op1BaseType}[] first = new {Op1BaseType}[Op1ElementCount]; + {Op1BaseType}[] falseVal = new {Op1BaseType}[Op1ElementCount]; + {RetBaseType}[] result = new {RetBaseType}[RetElementCount]; + Unsafe.WriteUnaligned(ref Unsafe.As<{Op1BaseType}, byte>(ref mask[0]), maskOp); + Unsafe.WriteUnaligned(ref Unsafe.As<{Op1BaseType}, byte>(ref first[0]), firstOp); + Unsafe.WriteUnaligned(ref Unsafe.As<{Op1BaseType}, byte>(ref falseVal[0]), falseOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{RetBaseType}, byte>(ref result[0]), ref Unsafe.AsRef(output), (uint)Unsafe.SizeOf<{RetVectorType}<{RetBaseType}>>()); + bool succeeded = true; + {TemplateValidationLogicForCndSel} + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof({Isa})}.{nameof({Isa}.{Method})}<{RetBaseType}>({Op1VectorType}<{Op1BaseType}>): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" mask: ({string.Join(", ", mask)})"); + TestLibrary.TestFramework.LogInformation($" first: ({string.Join(", ", first)})"); + TestLibrary.TestFramework.LogInformation($" falseOp: ({string.Join(", ", falseVal)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + Succeeded = false; + } + } + + private void ValidateResult({Op1VectorType}<{Op1BaseType}> op, byte imm, void* result, bool testValid = true, [CallerMemberName] string method = "") + { + {Op1BaseType}[] inArray = new {Op1BaseType}[Op1ElementCount]; + {RetBaseType}[] outArray = new {RetBaseType}[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As<{Op1BaseType}, byte>(ref inArray[0]), op); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{RetBaseType}, byte>(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf<{RetVectorType}<{RetBaseType}>>()); + + ValidateResult(inArray, imm, outArray, testValid, method); + } + + private void ValidateResult(void* op, byte imm, void* result, bool testValid = true, [CallerMemberName] string method = "") + { + {Op1BaseType}[] inArray = new {Op1BaseType}[Op1ElementCount]; + {RetBaseType}[] outArray = new {RetBaseType}[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{Op1BaseType}, byte>(ref inArray[0]), ref Unsafe.AsRef(op), (uint)Unsafe.SizeOf<{Op1VectorType}<{Op1BaseType}>>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{RetBaseType}, byte>(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf<{RetVectorType}<{RetBaseType}>>()); + + ValidateResult(inArray, imm, outArray, testValid, method); + } + + private void ValidateResult({Op1BaseType}[] firstOp, byte imm, {RetBaseType}[] result, bool testValid = true, [CallerMemberName] string method = "") + { + bool succeeded = true; + + {TemplateValidationLogic} + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof({Isa})}.{nameof({Isa}.{Method})}<{RetBaseType}>({Op1VectorType}<{Op1BaseType}>, byte): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" imm: ({string.Join(", ", imm)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} From 98208f621b98aa3924829c74fcd3e9d1e704437d Mon Sep 17 00:00:00 2001 From: Swapnil Gaikwad Date: Mon, 10 Jun 2024 15:54:02 +0100 Subject: [PATCH 2/7] Fix build errors from API mismatch --- .../ref/System.Runtime.Intrinsics.cs | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) 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 31a82e71bee6e1..b77fcc5a85c235 100644 --- a/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs +++ b/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs @@ -4378,16 +4378,16 @@ internal Arm64() { } public static System.Numerics.Vector DotProductBySelectedScalar(System.Numerics.Vector addend, System.Numerics.Vector left, System.Numerics.Vector right, [ConstantExpected] byte rightIndex) { throw null; } public static System.Numerics.Vector DotProductBySelectedScalar(System.Numerics.Vector addend, System.Numerics.Vector left, System.Numerics.Vector right, [ConstantExpected] byte rightIndex) { throw null; } - public static System.Numerics.Vector DuplicateSelectedScalarToVector(System.Numerics.Vector data, [ConstantExpected] byte index) { throw null; } - public static System.Numerics.Vector DuplicateSelectedScalarToVector(System.Numerics.Vector data, [ConstantExpected] byte index) { throw null; } - public static System.Numerics.Vector DuplicateSelectedScalarToVector(System.Numerics.Vector data, [ConstantExpected] byte index) { throw null; } - public static System.Numerics.Vector DuplicateSelectedScalarToVector(System.Numerics.Vector data, [ConstantExpected] byte index) { throw null; } - public static System.Numerics.Vector DuplicateSelectedScalarToVector(System.Numerics.Vector data, [ConstantExpected] byte index) { throw null; } - public static System.Numerics.Vector DuplicateSelectedScalarToVector(System.Numerics.Vector data, [ConstantExpected] byte index) { throw null; } - public static System.Numerics.Vector DuplicateSelectedScalarToVector(System.Numerics.Vector data, [ConstantExpected] byte index) { throw null; } - public static System.Numerics.Vector DuplicateSelectedScalarToVector(System.Numerics.Vector data, [ConstantExpected] byte index) { throw null; } - public static System.Numerics.Vector DuplicateSelectedScalarToVector(System.Numerics.Vector data, [ConstantExpected] byte index) { throw null; } - public static System.Numerics.Vector DuplicateSelectedScalarToVector(System.Numerics.Vector data, [ConstantExpected] byte index) { throw null; } + public static System.Numerics.Vector DuplicateSelectedScalarToVector(System.Numerics.Vector data, [System.Diagnostics.CodeAnalysis.ConstantExpectedAttribute(Min = 0, Max = (byte)(63))] byte index) { throw null; } + public static System.Numerics.Vector DuplicateSelectedScalarToVector(System.Numerics.Vector data, [System.Diagnostics.CodeAnalysis.ConstantExpectedAttribute(Min = 0, Max = (byte)(7))] byte index) { throw null; } + public static System.Numerics.Vector DuplicateSelectedScalarToVector(System.Numerics.Vector data, [System.Diagnostics.CodeAnalysis.ConstantExpectedAttribute(Min = 0, Max = (byte)(31))] byte index) { throw null; } + public static System.Numerics.Vector DuplicateSelectedScalarToVector(System.Numerics.Vector data, [System.Diagnostics.CodeAnalysis.ConstantExpectedAttribute(Min = 0, Max = (byte)(15))] byte index) { throw null; } + public static System.Numerics.Vector DuplicateSelectedScalarToVector(System.Numerics.Vector data, [System.Diagnostics.CodeAnalysis.ConstantExpectedAttribute(Min = 0, Max = (byte)(7))] byte index) { throw null; } + public static System.Numerics.Vector DuplicateSelectedScalarToVector(System.Numerics.Vector data, [System.Diagnostics.CodeAnalysis.ConstantExpectedAttribute(Min = 0, Max = (byte)(63))] byte index) { throw null; } + public static System.Numerics.Vector DuplicateSelectedScalarToVector(System.Numerics.Vector data, [System.Diagnostics.CodeAnalysis.ConstantExpectedAttribute(Min = 0, Max = (byte)(15))] byte index) { throw null; } + public static System.Numerics.Vector DuplicateSelectedScalarToVector(System.Numerics.Vector data, [System.Diagnostics.CodeAnalysis.ConstantExpectedAttribute(Min = 0, Max = (byte)(31))] byte index) { throw null; } + public static System.Numerics.Vector DuplicateSelectedScalarToVector(System.Numerics.Vector data, [System.Diagnostics.CodeAnalysis.ConstantExpectedAttribute(Min = 0, Max = (byte)(15))] byte index) { throw null; } + public static System.Numerics.Vector DuplicateSelectedScalarToVector(System.Numerics.Vector data, [System.Diagnostics.CodeAnalysis.ConstantExpectedAttribute(Min = 0, Max = (byte)(7))] byte index) { throw null; } public static System.Numerics.Vector FusedMultiplyAdd(System.Numerics.Vector addend, System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } public static System.Numerics.Vector FusedMultiplyAdd(System.Numerics.Vector addend, System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } From 39f4a316ed82b71fa5deabaaeec75c4b1cf681fc Mon Sep 17 00:00:00 2001 From: Swapnil Gaikwad Date: Mon, 10 Jun 2024 16:27:36 +0100 Subject: [PATCH 3/7] Use ConstantExpected instead of ConstantExpectedAttribute --- .../ref/System.Runtime.Intrinsics.cs | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) 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 b77fcc5a85c235..982f4977174757 100644 --- a/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs +++ b/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs @@ -4378,16 +4378,16 @@ internal Arm64() { } public static System.Numerics.Vector DotProductBySelectedScalar(System.Numerics.Vector addend, System.Numerics.Vector left, System.Numerics.Vector right, [ConstantExpected] byte rightIndex) { throw null; } public static System.Numerics.Vector DotProductBySelectedScalar(System.Numerics.Vector addend, System.Numerics.Vector left, System.Numerics.Vector right, [ConstantExpected] byte rightIndex) { throw null; } - public static System.Numerics.Vector DuplicateSelectedScalarToVector(System.Numerics.Vector data, [System.Diagnostics.CodeAnalysis.ConstantExpectedAttribute(Min = 0, Max = (byte)(63))] byte index) { throw null; } - public static System.Numerics.Vector DuplicateSelectedScalarToVector(System.Numerics.Vector data, [System.Diagnostics.CodeAnalysis.ConstantExpectedAttribute(Min = 0, Max = (byte)(7))] byte index) { throw null; } - public static System.Numerics.Vector DuplicateSelectedScalarToVector(System.Numerics.Vector data, [System.Diagnostics.CodeAnalysis.ConstantExpectedAttribute(Min = 0, Max = (byte)(31))] byte index) { throw null; } - public static System.Numerics.Vector DuplicateSelectedScalarToVector(System.Numerics.Vector data, [System.Diagnostics.CodeAnalysis.ConstantExpectedAttribute(Min = 0, Max = (byte)(15))] byte index) { throw null; } - public static System.Numerics.Vector DuplicateSelectedScalarToVector(System.Numerics.Vector data, [System.Diagnostics.CodeAnalysis.ConstantExpectedAttribute(Min = 0, Max = (byte)(7))] byte index) { throw null; } - public static System.Numerics.Vector DuplicateSelectedScalarToVector(System.Numerics.Vector data, [System.Diagnostics.CodeAnalysis.ConstantExpectedAttribute(Min = 0, Max = (byte)(63))] byte index) { throw null; } - public static System.Numerics.Vector DuplicateSelectedScalarToVector(System.Numerics.Vector data, [System.Diagnostics.CodeAnalysis.ConstantExpectedAttribute(Min = 0, Max = (byte)(15))] byte index) { throw null; } - public static System.Numerics.Vector DuplicateSelectedScalarToVector(System.Numerics.Vector data, [System.Diagnostics.CodeAnalysis.ConstantExpectedAttribute(Min = 0, Max = (byte)(31))] byte index) { throw null; } - public static System.Numerics.Vector DuplicateSelectedScalarToVector(System.Numerics.Vector data, [System.Diagnostics.CodeAnalysis.ConstantExpectedAttribute(Min = 0, Max = (byte)(15))] byte index) { throw null; } - public static System.Numerics.Vector DuplicateSelectedScalarToVector(System.Numerics.Vector data, [System.Diagnostics.CodeAnalysis.ConstantExpectedAttribute(Min = 0, Max = (byte)(7))] byte index) { throw null; } + public static System.Numerics.Vector DuplicateSelectedScalarToVector(System.Numerics.Vector data, [ConstantExpected(Min = 0, Max = (byte)(63))] byte index) { throw null; } + public static System.Numerics.Vector DuplicateSelectedScalarToVector(System.Numerics.Vector data, [ConstantExpected(Min = 0, Max = (byte)(7))] byte index) { throw null; } + public static System.Numerics.Vector DuplicateSelectedScalarToVector(System.Numerics.Vector data, [ConstantExpected(Min = 0, Max = (byte)(31))] byte index) { throw null; } + public static System.Numerics.Vector DuplicateSelectedScalarToVector(System.Numerics.Vector data, [ConstantExpected(Min = 0, Max = (byte)(15))] byte index) { throw null; } + public static System.Numerics.Vector DuplicateSelectedScalarToVector(System.Numerics.Vector data, [ConstantExpected(Min = 0, Max = (byte)(7))] byte index) { throw null; } + public static System.Numerics.Vector DuplicateSelectedScalarToVector(System.Numerics.Vector data, [ConstantExpected(Min = 0, Max = (byte)(63))] byte index) { throw null; } + public static System.Numerics.Vector DuplicateSelectedScalarToVector(System.Numerics.Vector data, [ConstantExpected(Min = 0, Max = (byte)(15))] byte index) { throw null; } + public static System.Numerics.Vector DuplicateSelectedScalarToVector(System.Numerics.Vector data, [ConstantExpected(Min = 0, Max = (byte)(31))] byte index) { throw null; } + public static System.Numerics.Vector DuplicateSelectedScalarToVector(System.Numerics.Vector data, [ConstantExpected(Min = 0, Max = (byte)(15))] byte index) { throw null; } + public static System.Numerics.Vector DuplicateSelectedScalarToVector(System.Numerics.Vector data, [ConstantExpected(Min = 0, Max = (byte)(7))] byte index) { throw null; } public static System.Numerics.Vector FusedMultiplyAdd(System.Numerics.Vector addend, System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } public static System.Numerics.Vector FusedMultiplyAdd(System.Numerics.Vector addend, System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } From 76acc39357bd91673d8dfc44ef8ba9aa8bc03a41 Mon Sep 17 00:00:00 2001 From: Swapnil Gaikwad Date: Mon, 10 Jun 2024 17:26:02 +0100 Subject: [PATCH 4/7] Fix API incompatibility in Sve.PlatformNotSupported.cs --- .../Arm/Sve.PlatformNotSupported.cs | 20 +++++++++---------- .../ref/System.Runtime.Intrinsics.cs | 20 +++++++++---------- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/Sve.PlatformNotSupported.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/Sve.PlatformNotSupported.cs index d369d01a511626..d6d3e41e71a9bd 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/Sve.PlatformNotSupported.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/Sve.PlatformNotSupported.cs @@ -1367,61 +1367,61 @@ internal Arm64() { } /// svuint8_t svdup_lane[_u8](svuint8_t data, uint8_t index) /// DUP Zresult.B, Zdata.B[index] /// - public static unsafe Vector DuplicateSelectedScalarToVector(Vector data, [ConstantExpected] byte index) { throw new PlatformNotSupportedException(); } + public static unsafe Vector DuplicateSelectedScalarToVector(Vector data, [ConstantExpected(Min = 0, Max = (byte)(63))] byte index) { throw new PlatformNotSupportedException(); } /// /// svfloat64_t svdup_lane[_f64](svfloat64_t data, uint64_t index) /// DUP Zresult.D, Zdata.D[index] /// - public static unsafe Vector DuplicateSelectedScalarToVector(Vector data, [ConstantExpected] byte index) { throw new PlatformNotSupportedException(); } + public static unsafe Vector DuplicateSelectedScalarToVector(Vector data, [ConstantExpected(Min = 0, Max = (byte)(7))] byte index) { throw new PlatformNotSupportedException(); } /// /// svint16_t svdup_lane[_s16](svint16_t data, uint16_t index) /// DUP Zresult.H, Zdata.H[index] /// - public static unsafe Vector DuplicateSelectedScalarToVector(Vector data, [ConstantExpected] byte index) { throw new PlatformNotSupportedException(); } + public static unsafe Vector DuplicateSelectedScalarToVector(Vector data, [ConstantExpected(Min = 0, Max = (byte)(31))] byte index) { throw new PlatformNotSupportedException(); } /// /// svint32_t svdup_lane[_s32](svint32_t data, uint32_t index) /// DUP Zresult.S, Zdata.S[index] /// - public static unsafe Vector DuplicateSelectedScalarToVector(Vector data, [ConstantExpected] byte index) { throw new PlatformNotSupportedException(); } + public static unsafe Vector DuplicateSelectedScalarToVector(Vector data, [ConstantExpected(Min = 0, Max = (byte)(15))] byte index) { throw new PlatformNotSupportedException(); } /// /// svint64_t svdup_lane[_s64](svint64_t data, uint64_t index) /// DUP Zresult.D, Zdata.D[index] /// - public static unsafe Vector DuplicateSelectedScalarToVector(Vector data, [ConstantExpected] byte index) { throw new PlatformNotSupportedException(); } + public static unsafe Vector DuplicateSelectedScalarToVector(Vector data, [ConstantExpected(Min = 0, Max = (byte)(7))] byte index) { throw new PlatformNotSupportedException(); } /// /// svint8_t svdup_lane[_s8](svint8_t data, uint8_t index) /// DUP Zresult.B, Zdata.B[index] /// - public static unsafe Vector DuplicateSelectedScalarToVector(Vector data, [ConstantExpected] byte index) { throw new PlatformNotSupportedException(); } + public static unsafe Vector DuplicateSelectedScalarToVector(Vector data, [ConstantExpected(Min = 0, Max = (byte)(63))] byte index) { throw new PlatformNotSupportedException(); } /// /// svfloat32_t svdup_lane[_f32](svfloat32_t data, uint32_t index) /// DUP Zresult.S, Zdata.S[index] /// - public static unsafe Vector DuplicateSelectedScalarToVector(Vector data, [ConstantExpected] byte index) { throw new PlatformNotSupportedException(); } + public static unsafe Vector DuplicateSelectedScalarToVector(Vector data, [ConstantExpected(Min = 0, Max = (byte)(15))] byte index) { throw new PlatformNotSupportedException(); } /// /// svuint16_t svdup_lane[_u16](svuint16_t data, uint16_t index) /// DUP Zresult.H, Zdata.H[index] /// - public static unsafe Vector DuplicateSelectedScalarToVector(Vector data, [ConstantExpected] byte index) { throw new PlatformNotSupportedException(); } + public static unsafe Vector DuplicateSelectedScalarToVector(Vector data, [ConstantExpected(Min = 0, Max = (byte)(31))] byte index) { throw new PlatformNotSupportedException(); } /// /// svuint32_t svdup_lane[_u32](svuint32_t data, uint32_t index) /// DUP Zresult.S, Zdata.S[index] /// - public static unsafe Vector DuplicateSelectedScalarToVector(Vector data, [ConstantExpected] byte index) { throw new PlatformNotSupportedException(); } + public static unsafe Vector DuplicateSelectedScalarToVector(Vector data, [ConstantExpected(Min = 0, Max = (byte)(15))] byte index) { throw new PlatformNotSupportedException(); } /// /// svuint64_t svdup_lane[_u64](svuint64_t data, uint64_t index) /// DUP Zresult.D, Zdata.D[index] /// - public static unsafe Vector DuplicateSelectedScalarToVector(Vector data, [ConstantExpected] byte index) { throw new PlatformNotSupportedException(); } + public static unsafe Vector DuplicateSelectedScalarToVector(Vector data, [ConstantExpected(Min = 0, Max = (byte)(7))] byte index) { throw new PlatformNotSupportedException(); } /// FusedMultiplyAdd : Multiply-add, addend first 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 982f4977174757..d31dae9f44f63f 100644 --- a/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs +++ b/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs @@ -4378,16 +4378,16 @@ internal Arm64() { } public static System.Numerics.Vector DotProductBySelectedScalar(System.Numerics.Vector addend, System.Numerics.Vector left, System.Numerics.Vector right, [ConstantExpected] byte rightIndex) { throw null; } public static System.Numerics.Vector DotProductBySelectedScalar(System.Numerics.Vector addend, System.Numerics.Vector left, System.Numerics.Vector right, [ConstantExpected] byte rightIndex) { throw null; } - public static System.Numerics.Vector DuplicateSelectedScalarToVector(System.Numerics.Vector data, [ConstantExpected(Min = 0, Max = (byte)(63))] byte index) { throw null; } - public static System.Numerics.Vector DuplicateSelectedScalarToVector(System.Numerics.Vector data, [ConstantExpected(Min = 0, Max = (byte)(7))] byte index) { throw null; } - public static System.Numerics.Vector DuplicateSelectedScalarToVector(System.Numerics.Vector data, [ConstantExpected(Min = 0, Max = (byte)(31))] byte index) { throw null; } - public static System.Numerics.Vector DuplicateSelectedScalarToVector(System.Numerics.Vector data, [ConstantExpected(Min = 0, Max = (byte)(15))] byte index) { throw null; } - public static System.Numerics.Vector DuplicateSelectedScalarToVector(System.Numerics.Vector data, [ConstantExpected(Min = 0, Max = (byte)(7))] byte index) { throw null; } - public static System.Numerics.Vector DuplicateSelectedScalarToVector(System.Numerics.Vector data, [ConstantExpected(Min = 0, Max = (byte)(63))] byte index) { throw null; } - public static System.Numerics.Vector DuplicateSelectedScalarToVector(System.Numerics.Vector data, [ConstantExpected(Min = 0, Max = (byte)(15))] byte index) { throw null; } - public static System.Numerics.Vector DuplicateSelectedScalarToVector(System.Numerics.Vector data, [ConstantExpected(Min = 0, Max = (byte)(31))] byte index) { throw null; } - public static System.Numerics.Vector DuplicateSelectedScalarToVector(System.Numerics.Vector data, [ConstantExpected(Min = 0, Max = (byte)(15))] byte index) { throw null; } - public static System.Numerics.Vector DuplicateSelectedScalarToVector(System.Numerics.Vector data, [ConstantExpected(Min = 0, Max = (byte)(7))] byte index) { throw null; } + public static System.Numerics.Vector DuplicateSelectedScalarToVector(System.Numerics.Vector data, [ConstantExpected(Min = 0, Max = (byte)(63))] byte index) { throw null; } + public static System.Numerics.Vector DuplicateSelectedScalarToVector(System.Numerics.Vector data, [ConstantExpected(Min = 0, Max = (byte)(7))] byte index) { throw null; } + public static System.Numerics.Vector DuplicateSelectedScalarToVector(System.Numerics.Vector data, [ConstantExpected(Min = 0, Max = (byte)(31))] byte index) { throw null; } + public static System.Numerics.Vector DuplicateSelectedScalarToVector(System.Numerics.Vector data, [ConstantExpected(Min = 0, Max = (byte)(15))] byte index) { throw null; } + public static System.Numerics.Vector DuplicateSelectedScalarToVector(System.Numerics.Vector data, [ConstantExpected(Min = 0, Max = (byte)(7))] byte index) { throw null; } + public static System.Numerics.Vector DuplicateSelectedScalarToVector(System.Numerics.Vector data, [ConstantExpected(Min = 0, Max = (byte)(63))] byte index) { throw null; } + public static System.Numerics.Vector DuplicateSelectedScalarToVector(System.Numerics.Vector data, [ConstantExpected(Min = 0, Max = (byte)(15))] byte index) { throw null; } + public static System.Numerics.Vector DuplicateSelectedScalarToVector(System.Numerics.Vector data, [ConstantExpected(Min = 0, Max = (byte)(31))] byte index) { throw null; } + public static System.Numerics.Vector DuplicateSelectedScalarToVector(System.Numerics.Vector data, [ConstantExpected(Min = 0, Max = (byte)(15))] byte index) { throw null; } + public static System.Numerics.Vector DuplicateSelectedScalarToVector(System.Numerics.Vector data, [ConstantExpected(Min = 0, Max = (byte)(7))] byte index) { throw null; } public static System.Numerics.Vector FusedMultiplyAdd(System.Numerics.Vector addend, System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } public static System.Numerics.Vector FusedMultiplyAdd(System.Numerics.Vector addend, System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } From c4db535abd05ebd22644de4a117b64cc6e19969a Mon Sep 17 00:00:00 2001 From: Swapnil Gaikwad Date: Tue, 11 Jun 2024 15:05:07 +0100 Subject: [PATCH 5/7] Fix emitting larger than 9-bit immediate with Sve LDR/STR instructions --- src/coreclr/jit/codegen.h | 7 +++++++ src/coreclr/jit/codegenarm64.cpp | 13 ++++++++++++- src/coreclr/jit/emitarm64.cpp | 16 ++++++++++++---- 3 files changed, 31 insertions(+), 5 deletions(-) diff --git a/src/coreclr/jit/codegen.h b/src/coreclr/jit/codegen.h index 5130c799832414..d28633d3fa2861 100644 --- a/src/coreclr/jit/codegen.h +++ b/src/coreclr/jit/codegen.h @@ -1615,6 +1615,13 @@ class CodeGen final : public CodeGenInterface void instGen_Set_Reg_To_Zero(emitAttr size, regNumber reg, insFlags flags = INS_FLAGS_DONT_CARE); + void instGen_Set_Reg_To_Base_Plus_Imm(emitAttr size, + regNumber dstReg, + regNumber baseReg, + ssize_t imm, + insFlags flags = INS_FLAGS_DONT_CARE DEBUGARG(size_t targetHandle = 0) + DEBUGARG(GenTreeFlags gtFlags = GTF_EMPTY)); + void instGen_Set_Reg_To_Imm(emitAttr size, regNumber reg, ssize_t imm, diff --git a/src/coreclr/jit/codegenarm64.cpp b/src/coreclr/jit/codegenarm64.cpp index 4ecbcc80a1ce75..6f4fd76ab652bc 100644 --- a/src/coreclr/jit/codegenarm64.cpp +++ b/src/coreclr/jit/codegenarm64.cpp @@ -2214,8 +2214,19 @@ void CodeGen::genEHCatchRet(BasicBlock* block) GetEmitter()->emitIns_R_L(INS_adr, EA_PTRSIZE, block->GetTarget(), REG_INTRET); } -// move an immediate value into an integer register +// move an immediate value + base address into an integer register +void CodeGen::instGen_Set_Reg_To_Base_Plus_Imm(emitAttr size, + regNumber dstReg, + regNumber baseReg, + ssize_t imm, + insFlags flags DEBUGARG(size_t targetHandle) + DEBUGARG(GenTreeFlags gtFlags)) +{ + instGen_Set_Reg_To_Imm(size, dstReg, imm); + GetEmitter()->emitIns_R_R_R(INS_add, size, dstReg, dstReg, baseReg); +} +// move an immediate value into an integer register void CodeGen::instGen_Set_Reg_To_Imm(emitAttr size, regNumber reg, ssize_t imm, diff --git a/src/coreclr/jit/emitarm64.cpp b/src/coreclr/jit/emitarm64.cpp index ff88d9fe29c98a..08f55317035868 100644 --- a/src/coreclr/jit/emitarm64.cpp +++ b/src/coreclr/jit/emitarm64.cpp @@ -7902,7 +7902,9 @@ void emitter::emitIns_R_S(instruction ins, emitAttr attr, regNumber reg1, int va { useRegForImm = true; regNumber rsvdReg = codeGen->rsGetRsvdReg(); - codeGen->instGen_Set_Reg_To_Imm(EA_PTRSIZE, rsvdReg, imm); + codeGen->instGen_Set_Reg_To_Base_Plus_Imm(EA_PTRSIZE, rsvdReg, reg2, imm); + reg2 = rsvdReg; + imm = 0; } } break; @@ -7930,7 +7932,9 @@ void emitter::emitIns_R_S(instruction ins, emitAttr attr, regNumber reg1, int va { useRegForImm = true; regNumber rsvdReg = codeGen->rsGetRsvdReg(); - codeGen->instGen_Set_Reg_To_Imm(EA_PTRSIZE, rsvdReg, imm); + codeGen->instGen_Set_Reg_To_Base_Plus_Imm(EA_PTRSIZE, rsvdReg, reg2, imm); + reg2 = rsvdReg; + imm = 0; } } break; @@ -8181,7 +8185,9 @@ void emitter::emitIns_S_R(instruction ins, emitAttr attr, regNumber reg1, int va { useRegForImm = true; regNumber rsvdReg = codeGen->rsGetRsvdReg(); - codeGen->instGen_Set_Reg_To_Imm(EA_PTRSIZE, rsvdReg, imm); + codeGen->instGen_Set_Reg_To_Base_Plus_Imm(EA_PTRSIZE, rsvdReg, reg2, imm); + reg2 = rsvdReg; + imm = 0; } } break; @@ -8209,7 +8215,9 @@ void emitter::emitIns_S_R(instruction ins, emitAttr attr, regNumber reg1, int va { useRegForImm = true; regNumber rsvdReg = codeGen->rsGetRsvdReg(); - codeGen->instGen_Set_Reg_To_Imm(EA_PTRSIZE, rsvdReg, imm); + codeGen->instGen_Set_Reg_To_Base_Plus_Imm(EA_PTRSIZE, rsvdReg, reg2, imm); + reg2 = rsvdReg; + imm = 0; } } break; From f2d4a93a54ea552bd50560eb9bc585d3d5d6519f Mon Sep 17 00:00:00 2001 From: Swapnil Gaikwad Date: Thu, 20 Jun 2024 15:38:42 +0100 Subject: [PATCH 6/7] Add HW_Category_SIMDByIndexedElement flag --- src/coreclr/jit/compiler.h | 1 + src/coreclr/jit/emitarm64.cpp | 5 +- src/coreclr/jit/hwintrinsic.cpp | 8 +-- src/coreclr/jit/hwintrinsicarm64.cpp | 23 +++++-- src/coreclr/jit/hwintrinsiccodegenarm64.cpp | 40 ++++++----- src/coreclr/jit/hwintrinsiclistarm64sve.h | 2 +- src/coreclr/jit/lsraarm64.cpp | 7 +- src/coreclr/jit/rationalize.cpp | 8 +-- .../_SveImmUnaryOpTestTemplate.template | 66 ++++++++++--------- 9 files changed, 95 insertions(+), 65 deletions(-) diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index 7bf00c5cc84d62..7b9049df890791 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -4680,6 +4680,7 @@ class Compiler unsigned immNumber, var_types simdBaseType, CorInfoType simdBaseJitType, + CORINFO_CLASS_HANDLE op1ClsHnd, CORINFO_CLASS_HANDLE op2ClsHnd, CORINFO_CLASS_HANDLE op3ClsHnd, unsigned* immSimdSize, diff --git a/src/coreclr/jit/emitarm64.cpp b/src/coreclr/jit/emitarm64.cpp index 32e297a346ae55..7bc995a0890621 100644 --- a/src/coreclr/jit/emitarm64.cpp +++ b/src/coreclr/jit/emitarm64.cpp @@ -7899,12 +7899,13 @@ void emitter::emitIns_R_S(instruction ins, emitAttr attr, regNumber reg1, int va { useRegForImm = true; regNumber rsvdReg = codeGen->rsGetRsvdReg(); + // For larger imm values (> 9 bits), calculate base + imm in a reserved register first. codeGen->instGen_Set_Reg_To_Base_Plus_Imm(EA_PTRSIZE, rsvdReg, reg2, imm); reg2 = rsvdReg; imm = 0; } - break; } + break; default: NYI("emitIns_R_S"); // FP locals? @@ -8152,11 +8153,11 @@ void emitter::emitIns_S_R(instruction ins, emitAttr attr, regNumber reg1, int va { useRegForImm = true; regNumber rsvdReg = codeGen->rsGetRsvdReg(); + // For larger imm values (> 9 bits), calculate base + imm in a reserved register first. codeGen->instGen_Set_Reg_To_Base_Plus_Imm(EA_PTRSIZE, rsvdReg, reg2, imm); reg2 = rsvdReg; imm = 0; } - break; } break; diff --git a/src/coreclr/jit/hwintrinsic.cpp b/src/coreclr/jit/hwintrinsic.cpp index 3c6f394e395d18..68630c4511da78 100644 --- a/src/coreclr/jit/hwintrinsic.cpp +++ b/src/coreclr/jit/hwintrinsic.cpp @@ -1277,8 +1277,8 @@ GenTree* Compiler::impHWIntrinsic(NamedIntrinsic intrinsic, { unsigned immSimdSize = simdSize; var_types immSimdBaseType = simdBaseType; - getHWIntrinsicImmTypes(intrinsic, sig, 2, simdBaseType, simdBaseJitType, sigReader.op2ClsHnd, - sigReader.op3ClsHnd, &immSimdSize, &immSimdBaseType); + getHWIntrinsicImmTypes(intrinsic, sig, 2, simdBaseType, simdBaseJitType, sigReader.op1ClsHnd, + sigReader.op2ClsHnd, sigReader.op3ClsHnd, &immSimdSize, &immSimdBaseType); HWIntrinsicInfo::lookupImmBounds(intrinsic, immSimdSize, immSimdBaseType, 2, &immLowerBound, &immUpperBound); if (!CheckHWIntrinsicImmRange(intrinsic, simdBaseJitType, immOp2, mustExpand, immLowerBound, immUpperBound, @@ -1310,8 +1310,8 @@ GenTree* Compiler::impHWIntrinsic(NamedIntrinsic intrinsic, #ifdef TARGET_ARM64 unsigned immSimdSize = simdSize; var_types immSimdBaseType = simdBaseType; - getHWIntrinsicImmTypes(intrinsic, sig, 1, simdBaseType, simdBaseJitType, sigReader.op2ClsHnd, - sigReader.op3ClsHnd, &immSimdSize, &immSimdBaseType); + getHWIntrinsicImmTypes(intrinsic, sig, 1, simdBaseType, simdBaseJitType, sigReader.op1ClsHnd, + sigReader.op2ClsHnd, sigReader.op3ClsHnd, &immSimdSize, &immSimdBaseType); HWIntrinsicInfo::lookupImmBounds(intrinsic, immSimdSize, immSimdBaseType, 1, &immLowerBound, &immUpperBound); #else immUpperBound = HWIntrinsicInfo::lookupImmUpperBound(intrinsic); diff --git a/src/coreclr/jit/hwintrinsicarm64.cpp b/src/coreclr/jit/hwintrinsicarm64.cpp index 3d160e25f82883..8ff753bc885ec5 100644 --- a/src/coreclr/jit/hwintrinsicarm64.cpp +++ b/src/coreclr/jit/hwintrinsicarm64.cpp @@ -258,6 +258,7 @@ void Compiler::getHWIntrinsicImmOps(NamedIntrinsic intrinsic, // immNumber -- Which immediate to use (1 for most intrinsics) // simdBaseType -- base type of the intrinsic // simdType -- vector size of the intrinsic +// op1ClsHnd -- cls handler for op1 // op2ClsHnd -- cls handler for op2 // op2ClsHnd -- cls handler for op3 // immSimdSize [IN/OUT] -- Size of the immediate to override @@ -268,6 +269,7 @@ void Compiler::getHWIntrinsicImmTypes(NamedIntrinsic intrinsic, unsigned immNumber, var_types simdBaseType, CorInfoType simdBaseJitType, + CORINFO_CLASS_HANDLE op1ClsHnd, CORINFO_CLASS_HANDLE op2ClsHnd, CORINFO_CLASS_HANDLE op3ClsHnd, unsigned* immSimdSize, @@ -283,7 +285,12 @@ void Compiler::getHWIntrinsicImmTypes(NamedIntrinsic intrinsic, var_types indexedElementBaseType; *immSimdSize = 0; - if (sig->numArgs == 3) + if (sig->numArgs == 2) + { + indexedElementBaseJitType = getBaseJitTypeAndSizeOfSIMDType(op1ClsHnd, immSimdSize); + indexedElementBaseType = JitType2PreciseVarType(indexedElementBaseJitType); + } + else if (sig->numArgs == 3) { indexedElementBaseJitType = getBaseJitTypeAndSizeOfSIMDType(op2ClsHnd, immSimdSize); indexedElementBaseType = JitType2PreciseVarType(indexedElementBaseJitType); @@ -368,7 +375,15 @@ void HWIntrinsicInfo::lookupImmBounds( } else if (category == HW_Category_SIMDByIndexedElement) { - immUpperBound = Compiler::getSIMDVectorLength(simdSize, baseType) - 1; + if (intrinsic == NI_Sve_DuplicateSelectedScalarToVector) + { + // For SVE_DUP, the upper bound on index does not depend on the vector length. + immUpperBound = (512 / (BITS_PER_BYTE * genTypeSize(baseType))) - 1; + } + else + { + immUpperBound = Compiler::getSIMDVectorLength(simdSize, baseType) - 1; + } } else { @@ -415,10 +430,6 @@ void HWIntrinsicInfo::lookupImmBounds( immUpperBound = (int)SVE_PATTERN_ALL; break; - case NI_Sve_DuplicateSelectedScalarToVector: - immUpperBound = (512 / (genTypeSize(baseType) * BITS_PER_BYTE)) - 1; - break; - case NI_Sve_SaturatingDecrementBy16BitElementCount: case NI_Sve_SaturatingDecrementBy32BitElementCount: case NI_Sve_SaturatingDecrementBy64BitElementCount: diff --git a/src/coreclr/jit/hwintrinsiccodegenarm64.cpp b/src/coreclr/jit/hwintrinsiccodegenarm64.cpp index fd355fc77731ab..d26753c04711aa 100644 --- a/src/coreclr/jit/hwintrinsiccodegenarm64.cpp +++ b/src/coreclr/jit/hwintrinsiccodegenarm64.cpp @@ -61,7 +61,11 @@ CodeGen::HWIntrinsicImmOpHelper::HWIntrinsicImmOpHelper(CodeGen* codeGen, GenTre const HWIntrinsic intrinInfo(intrin); var_types indexedElementOpType; - if (intrinInfo.numOperands == 3) + if (intrinInfo.numOperands == 2) + { + indexedElementOpType = intrinInfo.op1->TypeGet(); + } + else if (intrinInfo.numOperands == 3) { indexedElementOpType = intrinInfo.op2->TypeGet(); } @@ -357,13 +361,28 @@ void CodeGen::genHWIntrinsic(GenTreeHWIntrinsic* node) } else { - HWIntrinsicImmOpHelper helper(this, intrin.op3, node); + if (intrin.numOperands == 2) + { + HWIntrinsicImmOpHelper helper(this, intrin.op2, node); - for (helper.EmitBegin(); !helper.Done(); helper.EmitCaseEnd()) + for (helper.EmitBegin(); !helper.Done(); helper.EmitCaseEnd()) + { + const int elementIndex = helper.ImmValue(); + + GetEmitter()->emitIns_R_R_I(ins, emitSize, targetReg, op1Reg, elementIndex, opt); + } + } + else { - const int elementIndex = helper.ImmValue(); + assert(intrin.numOperands == 3); + HWIntrinsicImmOpHelper helper(this, intrin.op3, node); + + for (helper.EmitBegin(); !helper.Done(); helper.EmitCaseEnd()) + { + const int elementIndex = helper.ImmValue(); - GetEmitter()->emitIns_R_R_R_I(ins, emitSize, targetReg, op1Reg, op2Reg, elementIndex, opt); + GetEmitter()->emitIns_R_R_R_I(ins, emitSize, targetReg, op1Reg, op2Reg, elementIndex, opt); + } } } } @@ -784,17 +803,6 @@ void CodeGen::genHWIntrinsic(GenTreeHWIntrinsic* node) unreached(); } } - else if (intrin.id == NI_Sve_DuplicateSelectedScalarToVector) - { - HWIntrinsicImmOpHelper helper(this, intrin.op2, node); - - for (helper.EmitBegin(); !helper.Done(); helper.EmitCaseEnd()) - { - const int elementIndex = helper.ImmValue(); - - GetEmitter()->emitIns_R_R_I(ins, emitSize, targetReg, op1Reg, elementIndex, opt); - } - } else { assert(!hasImmediateOperand); diff --git a/src/coreclr/jit/hwintrinsiclistarm64sve.h b/src/coreclr/jit/hwintrinsiclistarm64sve.h index 1ba906a7d2954a..74a00529e5763b 100644 --- a/src/coreclr/jit/hwintrinsiclistarm64sve.h +++ b/src/coreclr/jit/hwintrinsiclistarm64sve.h @@ -69,7 +69,7 @@ HARDWARE_INTRINSIC(Sve, CreateWhileLessThanOrEqualMask8Bit, HARDWARE_INTRINSIC(Sve, Divide, -1, 2, true, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_sdiv, INS_sve_udiv, INS_sve_sdiv, INS_sve_udiv, INS_sve_fdiv, INS_sve_fdiv}, HW_Category_SIMD, HW_Flag_Scalable|HW_Flag_EmbeddedMaskedOperation|HW_Flag_HasRMWSemantics|HW_Flag_LowMaskedOperation) HARDWARE_INTRINSIC(Sve, DotProduct, -1, 3, true, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_sdot, INS_sve_udot, INS_sve_sdot, INS_sve_udot, INS_invalid, INS_invalid}, HW_Category_SIMD, HW_Flag_Scalable|HW_Flag_HasRMWSemantics) HARDWARE_INTRINSIC(Sve, DotProductBySelectedScalar, -1, 4, true, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_sdot, INS_sve_udot, INS_sve_sdot, INS_sve_udot, INS_invalid, INS_invalid}, HW_Category_SIMDByIndexedElement, HW_Flag_Scalable|HW_Flag_BaseTypeFromFirstArg|HW_Flag_HasImmediateOperand|HW_Flag_HasRMWSemantics|HW_Flag_LowVectorOperation) -HARDWARE_INTRINSIC(Sve, DuplicateSelectedScalarToVector, -1, 2, true, {INS_sve_dup, INS_sve_dup, INS_sve_dup, INS_sve_dup, INS_sve_dup, INS_sve_dup, INS_sve_dup, INS_sve_dup, INS_sve_dup, INS_sve_dup}, HW_Category_SIMD, HW_Flag_Scalable|HW_Flag_HasImmediateOperand) +HARDWARE_INTRINSIC(Sve, DuplicateSelectedScalarToVector, -1, 2, true, {INS_sve_dup, INS_sve_dup, INS_sve_dup, INS_sve_dup, INS_sve_dup, INS_sve_dup, INS_sve_dup, INS_sve_dup, INS_sve_dup, INS_sve_dup}, HW_Category_SIMDByIndexedElement, HW_Flag_Scalable|HW_Flag_HasImmediateOperand) HARDWARE_INTRINSIC(Sve, FusedMultiplyAdd, -1, -1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_fmla, INS_sve_fmla}, HW_Category_SIMD, HW_Flag_Scalable|HW_Flag_EmbeddedMaskedOperation|HW_Flag_HasRMWSemantics|HW_Flag_LowMaskedOperation|HW_Flag_FmaIntrinsic|HW_Flag_SpecialCodeGen) HARDWARE_INTRINSIC(Sve, FusedMultiplyAddBySelectedScalar, -1, 4, true, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_fmla, INS_sve_fmla}, HW_Category_SIMDByIndexedElement, HW_Flag_Scalable|HW_Flag_HasImmediateOperand|HW_Flag_HasRMWSemantics|HW_Flag_FmaIntrinsic|HW_Flag_LowVectorOperation) HARDWARE_INTRINSIC(Sve, FusedMultiplyAddNegated, -1, -1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_fnmla, INS_sve_fnmla}, HW_Category_SIMD, HW_Flag_Scalable|HW_Flag_EmbeddedMaskedOperation|HW_Flag_HasRMWSemantics|HW_Flag_LowMaskedOperation|HW_Flag_FmaIntrinsic|HW_Flag_SpecialCodeGen) diff --git a/src/coreclr/jit/lsraarm64.cpp b/src/coreclr/jit/lsraarm64.cpp index b84b0463f8c559..39927678ab7e03 100644 --- a/src/coreclr/jit/lsraarm64.cpp +++ b/src/coreclr/jit/lsraarm64.cpp @@ -1371,7 +1371,11 @@ int LinearScan::BuildHWIntrinsic(GenTreeHWIntrinsic* intrinsicTree, int* pDstCou { var_types indexedElementOpType; - if (intrin.numOperands == 3) + if (intrin.numOperands == 2) + { + indexedElementOpType = intrin.op1->TypeGet(); + } + else if (intrin.numOperands == 3) { indexedElementOpType = intrin.op2->TypeGet(); } @@ -1434,7 +1438,6 @@ int LinearScan::BuildHWIntrinsic(GenTreeHWIntrinsic* intrinsicTree, int* pDstCou case NI_AdvSimd_Arm64_LoadAndInsertScalarVector128x3: case NI_AdvSimd_Arm64_LoadAndInsertScalarVector128x4: case NI_AdvSimd_Arm64_DuplicateSelectedScalarToVector128: - case NI_Sve_DuplicateSelectedScalarToVector: needBranchTargetReg = !intrin.op2->isContainedIntOrIImmed(); break; diff --git a/src/coreclr/jit/rationalize.cpp b/src/coreclr/jit/rationalize.cpp index a0f08f6dcdef07..0d2e03d4248790 100644 --- a/src/coreclr/jit/rationalize.cpp +++ b/src/coreclr/jit/rationalize.cpp @@ -457,8 +457,8 @@ void Rationalizer::RewriteHWIntrinsicAsUserCall(GenTree** use, ArrayStackgetHWIntrinsicImmTypes(intrinsicId, &sigInfo, 2, simdBaseType, simdBaseJitType, op2ClsHnd, - op3ClsHnd, &immSimdSize, &immSimdBaseType); + comp->getHWIntrinsicImmTypes(intrinsicId, &sigInfo, 2, simdBaseType, simdBaseJitType, op1ClsHnd, + op2ClsHnd, op3ClsHnd, &immSimdSize, &immSimdBaseType); HWIntrinsicInfo::lookupImmBounds(intrinsicId, immSimdSize, immSimdBaseType, 2, &immLowerBound, &immUpperBound); @@ -473,8 +473,8 @@ void Rationalizer::RewriteHWIntrinsicAsUserCall(GenTree** use, ArrayStackgetHWIntrinsicImmTypes(intrinsicId, &sigInfo, 1, simdBaseType, simdBaseJitType, op2ClsHnd, op3ClsHnd, - &immSimdSize, &immSimdBaseType); + comp->getHWIntrinsicImmTypes(intrinsicId, &sigInfo, 1, simdBaseType, simdBaseJitType, op1ClsHnd, op2ClsHnd, + op3ClsHnd, &immSimdSize, &immSimdBaseType); HWIntrinsicInfo::lookupImmBounds(intrinsicId, immSimdSize, immSimdBaseType, 1, &immLowerBound, &immUpperBound); #endif diff --git a/src/tests/JIT/HardwareIntrinsics/Arm/Shared/_SveImmUnaryOpTestTemplate.template b/src/tests/JIT/HardwareIntrinsics/Arm/Shared/_SveImmUnaryOpTestTemplate.template index b280d260ba2790..dbc66907536445 100644 --- a/src/tests/JIT/HardwareIntrinsics/Arm/Shared/_SveImmUnaryOpTestTemplate.template +++ b/src/tests/JIT/HardwareIntrinsics/Arm/Shared/_SveImmUnaryOpTestTemplate.template @@ -123,6 +123,7 @@ namespace JIT.HardwareIntrinsics.Arm private struct TestStruct { public {Op1VectorType}<{Op1BaseType}> _fld; + public byte _imm; public static TestStruct Create() { @@ -130,16 +131,17 @@ namespace JIT.HardwareIntrinsics.Arm for (var i = 0; i < Op1ElementCount; i++) { _data[i] = {NextValueOp1}; } Unsafe.CopyBlockUnaligned(ref Unsafe.As<{Op1VectorType}<{Op1BaseType}>, byte>(ref testStruct._fld), ref Unsafe.As<{Op1BaseType}, byte>(ref _data[0]), (uint)Unsafe.SizeOf<{Op1VectorType}<{Op1BaseType}>>()); + testStruct._imm = (byte)({Imm}); return testStruct; } public void RunStructFldScenario({TemplateName}UnaryOpTest__{TestName} testClass) { - var result = {Isa}.{Method}(_fld, {Imm}); + var result = {Isa}.{Method}(_fld, _imm); Unsafe.Write(testClass._dataTable.outArrayPtr, result); - testClass.ValidateResult(_fld, {Imm}, testClass._dataTable.outArrayPtr); + testClass.ValidateResult(_fld, _imm, testClass._dataTable.outArrayPtr); } } @@ -147,7 +149,7 @@ namespace JIT.HardwareIntrinsics.Arm private static readonly int Op1ElementCount = Unsafe.SizeOf<{Op1VectorType}<{Op1BaseType}>>() / sizeof({Op1BaseType}); private static readonly int RetElementCount = Unsafe.SizeOf<{RetVectorType}<{RetBaseType}>>() / sizeof({RetBaseType}); - private static readonly byte Imm = {Imm}; + private static readonly byte Imm = (byte)({Imm}); private static {Op1BaseType}[] _maskData = new {Op1BaseType}[Op1ElementCount]; private static {Op1BaseType}[] _data = new {Op1BaseType}[Op1ElementCount]; @@ -181,27 +183,31 @@ namespace JIT.HardwareIntrinsics.Arm var result = {Isa}.{Method}( Unsafe.Read<{Op1VectorType}<{Op1BaseType}>>(_dataTable.inArrayPtr), - {Imm} + Imm ); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_dataTable.inArrayPtr, {Imm}, _dataTable.outArrayPtr); + ValidateResult(_dataTable.inArrayPtr, Imm, _dataTable.outArrayPtr); } public void RunBasicScenario_UnsafeRead_InvalidImm() { TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead_InvalidImm)); - var result = {Isa}.{Method}( - Unsafe.Read<{Op1VectorType}<{Op1BaseType}>>(_dataTable.inArrayPtr), - {InvalidImm} - ); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_dataTable.inArrayPtr, {InvalidImm}, _dataTable.outArrayPtr, false); + bool succeeded = false; + try + { + var result = {Isa}.{Method}( + Unsafe.Read<{Op1VectorType}<{Op1BaseType}>>(_dataTable.inArrayPtr), + {InvalidImm} + ); + } + catch (ArgumentOutOfRangeException) + { + succeeded = true; + } } - public void RunBasicScenario_Load() { TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); @@ -210,11 +216,11 @@ namespace JIT.HardwareIntrinsics.Arm var result = {Isa}.{Method}( {LoadIsa}.Load{Op1VectorType}(loadMask, ({Op1BaseType}*)(_dataTable.inArrayPtr)), - {Imm} + Imm ); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_dataTable.inArrayPtr, {Imm}, _dataTable.outArrayPtr); + ValidateResult(_dataTable.inArrayPtr, Imm, _dataTable.outArrayPtr); } public void RunReflectionScenario_UnsafeRead() @@ -224,11 +230,11 @@ namespace JIT.HardwareIntrinsics.Arm var result = typeof({Isa}).GetMethod(nameof({Isa}.{Method}), new Type[] { typeof({Op1VectorType}<{Op1BaseType}>), typeof(byte) }) .Invoke(null, new object[] { Unsafe.Read<{Op1VectorType}<{Op1BaseType}>>(_dataTable.inArrayPtr), - (byte){Imm} + Imm }); Unsafe.Write(_dataTable.outArrayPtr, ({RetVectorType}<{RetBaseType}>)(result)); - ValidateResult(_dataTable.inArrayPtr, {Imm}, _dataTable.outArrayPtr); + ValidateResult(_dataTable.inArrayPtr, Imm, _dataTable.outArrayPtr); } public void RunLclVarScenario_UnsafeRead() @@ -236,20 +242,20 @@ namespace JIT.HardwareIntrinsics.Arm TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); var op = Unsafe.Read<{Op1VectorType}<{Op1BaseType}>>(_dataTable.inArrayPtr); - var result = {Isa}.{Method}(op, {Imm}); + var result = {Isa}.{Method}(op, Imm); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(op, {Imm}, _dataTable.outArrayPtr); + ValidateResult(op, Imm, _dataTable.outArrayPtr); } public void RunClassFldScenario() { TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); - var result = {Isa}.{Method}(_fld, {Imm}); + var result = {Isa}.{Method}(_fld, Imm); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_fld, {Imm}, _dataTable.outArrayPtr); + ValidateResult(_fld, Imm, _dataTable.outArrayPtr); } public void RunStructLclFldScenario() @@ -257,10 +263,10 @@ namespace JIT.HardwareIntrinsics.Arm TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); var test = TestStruct.Create(); - var result = {Isa}.{Method}(test._fld, {Imm}); + var result = {Isa}.{Method}(test._fld, test._imm); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(test._fld, {Imm}, _dataTable.outArrayPtr); + ValidateResult(test._fld, test._imm, _dataTable.outArrayPtr); } public void RunStructFldScenario() @@ -304,9 +310,9 @@ namespace JIT.HardwareIntrinsics.Arm [method: MethodImpl(MethodImplOptions.AggressiveInlining)] private void ConditionalSelectScenario({Op1VectorType}<{Op1BaseType}> mask, {Op1VectorType}<{Op1BaseType}> op, {Op1VectorType}<{Op1BaseType}> falseOp) { - var result = Sve.ConditionalSelect(mask, {Isa}.{Method}(op, {Imm}), falseOp); + var result = Sve.ConditionalSelect(mask, {Isa}.{Method}(op, Imm), falseOp); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateConditionalSelectResult(mask, op, falseOp, {Imm}, _dataTable.outArrayPtr); + ValidateConditionalSelectResult(mask, op, falseOp, Imm, _dataTable.outArrayPtr); } public void RunUnsupportedScenario() @@ -353,7 +359,7 @@ namespace JIT.HardwareIntrinsics.Arm } } - private void ValidateResult({Op1VectorType}<{Op1BaseType}> op, byte imm, void* result, bool testValid = true, [CallerMemberName] string method = "") + private void ValidateResult({Op1VectorType}<{Op1BaseType}> op, byte imm, void* result, [CallerMemberName] string method = "") { {Op1BaseType}[] inArray = new {Op1BaseType}[Op1ElementCount]; {RetBaseType}[] outArray = new {RetBaseType}[RetElementCount]; @@ -361,10 +367,10 @@ namespace JIT.HardwareIntrinsics.Arm Unsafe.WriteUnaligned(ref Unsafe.As<{Op1BaseType}, byte>(ref inArray[0]), op); Unsafe.CopyBlockUnaligned(ref Unsafe.As<{RetBaseType}, byte>(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf<{RetVectorType}<{RetBaseType}>>()); - ValidateResult(inArray, imm, outArray, testValid, method); + ValidateResult(inArray, imm, outArray, method); } - private void ValidateResult(void* op, byte imm, void* result, bool testValid = true, [CallerMemberName] string method = "") + private void ValidateResult(void* op, byte imm, void* result, [CallerMemberName] string method = "") { {Op1BaseType}[] inArray = new {Op1BaseType}[Op1ElementCount]; {RetBaseType}[] outArray = new {RetBaseType}[RetElementCount]; @@ -372,10 +378,10 @@ namespace JIT.HardwareIntrinsics.Arm Unsafe.CopyBlockUnaligned(ref Unsafe.As<{Op1BaseType}, byte>(ref inArray[0]), ref Unsafe.AsRef(op), (uint)Unsafe.SizeOf<{Op1VectorType}<{Op1BaseType}>>()); Unsafe.CopyBlockUnaligned(ref Unsafe.As<{RetBaseType}, byte>(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf<{RetVectorType}<{RetBaseType}>>()); - ValidateResult(inArray, imm, outArray, testValid, method); + ValidateResult(inArray, imm, outArray, method); } - private void ValidateResult({Op1BaseType}[] firstOp, byte imm, {RetBaseType}[] result, bool testValid = true, [CallerMemberName] string method = "") + private void ValidateResult({Op1BaseType}[] firstOp, byte imm, {RetBaseType}[] result, [CallerMemberName] string method = "") { bool succeeded = true; From 7ce46627538338778bd6e5802093c131c731324e Mon Sep 17 00:00:00 2001 From: Swapnil Gaikwad Date: Wed, 26 Jun 2024 18:33:05 +0100 Subject: [PATCH 7/7] Fix issue for getting incorrect register type for op2 --- src/coreclr/jit/lsraarm64.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/coreclr/jit/lsraarm64.cpp b/src/coreclr/jit/lsraarm64.cpp index d5d40d64d03aa4..4c4c58fd00bf97 100644 --- a/src/coreclr/jit/lsraarm64.cpp +++ b/src/coreclr/jit/lsraarm64.cpp @@ -1682,7 +1682,14 @@ int LinearScan::BuildHWIntrinsic(GenTreeHWIntrinsic* intrinsicTree, int* pDstCou { assert(!isRMW); - srcCount += BuildOperandUses(intrin.op2, RBM_ASIMD_INDEXED_H_ELEMENT_ALLOWED_REGS.GetFloatRegSet()); + if (intrin.id == NI_Sve_DuplicateSelectedScalarToVector) + { + srcCount += BuildOperandUses(intrin.op2); + } + else + { + srcCount += BuildOperandUses(intrin.op2, RBM_ASIMD_INDEXED_H_ELEMENT_ALLOWED_REGS.GetFloatRegSet()); + } if (intrin.op3 != nullptr) {