diff --git a/src/coreclr/jit/hwintrinsic.cpp b/src/coreclr/jit/hwintrinsic.cpp index 48dd3cffa10465..18dd3000e50c75 100644 --- a/src/coreclr/jit/hwintrinsic.cpp +++ b/src/coreclr/jit/hwintrinsic.cpp @@ -1607,6 +1607,12 @@ GenTree* Compiler::impHWIntrinsic(NamedIntrinsic intrinsic, assert(varTypeIsSIMD(op2->TypeGet())); retNode->AsHWIntrinsic()->SetAuxiliaryJitType(getBaseJitTypeOfSIMDType(sigReader.op2ClsHnd)); } +#elif defined(TARGET_ARM64) + if (intrinsic == NI_Sve_GatherVector) + { + assert(varTypeIsSIMD(op3->TypeGet())); + retNode->AsHWIntrinsic()->SetAuxiliaryJitType(getBaseJitTypeOfSIMDType(sigReader.op3ClsHnd)); + } #endif break; } diff --git a/src/coreclr/jit/hwintrinsiccodegenarm64.cpp b/src/coreclr/jit/hwintrinsiccodegenarm64.cpp index 23b09c0cef751e..b1494307cdd2eb 100644 --- a/src/coreclr/jit/hwintrinsiccodegenarm64.cpp +++ b/src/coreclr/jit/hwintrinsiccodegenarm64.cpp @@ -1845,6 +1845,37 @@ void CodeGen::genHWIntrinsic(GenTreeHWIntrinsic* node) break; } + case NI_Sve_GatherVector: + { + if (!varTypeIsSIMD(intrin.op2->gtType)) + { + // GatherVector(Vector mask, T* address, Vector indices) + + var_types auxType = node->GetAuxiliaryType(); + emitAttr auxSize = emitActualTypeSize(auxType); + + if (auxSize == EA_8BYTE) + { + opt = varTypeIsUnsigned(auxType) ? INS_OPTS_SCALABLE_D_UXTW : INS_OPTS_SCALABLE_D_SXTW; + } + else + { + assert(auxSize == EA_4BYTE); + opt = varTypeIsUnsigned(auxType) ? INS_OPTS_SCALABLE_S_UXTW : INS_OPTS_SCALABLE_S_SXTW; + } + + GetEmitter()->emitIns_R_R_R_R(ins, emitSize, targetReg, op1Reg, op2Reg, op3Reg, opt, INS_SCALABLE_OPTS_MOD_N); + } + else + { + // GatherVector(Vector mask, Vector addresses) + + GetEmitter()->emitIns_R_R_R_I(ins, emitSize, targetReg, op1Reg, op2Reg, 0, opt); + } + + break; + } + case NI_Sve_ReverseElement: // Use non-predicated version explicitly GetEmitter()->emitIns_R_R(ins, emitSize, targetReg, op1Reg, opt, INS_SCALABLE_OPTS_UNPREDICATED); diff --git a/src/coreclr/jit/hwintrinsiclistarm64sve.h b/src/coreclr/jit/hwintrinsiclistarm64sve.h index e047fc64447c14..405b06f3a76a1d 100644 --- a/src/coreclr/jit/hwintrinsiclistarm64sve.h +++ b/src/coreclr/jit/hwintrinsiclistarm64sve.h @@ -73,6 +73,9 @@ HARDWARE_INTRINSIC(Sve, FusedMultiplyAddNegated, HARDWARE_INTRINSIC(Sve, FusedMultiplySubtract, -1, -1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_fmls, INS_sve_fmls}, HW_Category_SIMD, HW_Flag_Scalable|HW_Flag_EmbeddedMaskedOperation|HW_Flag_HasRMWSemantics|HW_Flag_LowMaskedOperation|HW_Flag_FmaIntrinsic|HW_Flag_SpecialCodeGen) HARDWARE_INTRINSIC(Sve, FusedMultiplySubtractBySelectedScalar, -1, 4, true, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_fmls, INS_sve_fmls}, HW_Category_SIMDByIndexedElement, HW_Flag_Scalable|HW_Flag_HasImmediateOperand|HW_Flag_HasRMWSemantics|HW_Flag_FmaIntrinsic|HW_Flag_LowVectorOperation) HARDWARE_INTRINSIC(Sve, FusedMultiplySubtractNegated, -1, -1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_fnmls, INS_sve_fnmls}, HW_Category_SIMD, HW_Flag_Scalable|HW_Flag_EmbeddedMaskedOperation|HW_Flag_HasRMWSemantics|HW_Flag_LowMaskedOperation|HW_Flag_FmaIntrinsic|HW_Flag_SpecialCodeGen) + +HARDWARE_INTRINSIC(Sve, GatherVector, -1, -1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_ld1w, INS_sve_ld1w, INS_sve_ld1d, INS_sve_ld1d, INS_sve_ld1w, INS_sve_ld1d}, HW_Category_SIMD, HW_Flag_Scalable|HW_Flag_BaseTypeFromFirstArg|HW_Flag_SpecialCodeGen|HW_Flag_ExplicitMaskedOperation) + HARDWARE_INTRINSIC(Sve, GetActiveElementCount, -1, 2, true, {INS_sve_cntp, INS_sve_cntp, INS_sve_cntp, INS_sve_cntp, INS_sve_cntp, INS_sve_cntp, INS_sve_cntp, INS_sve_cntp, INS_sve_cntp, INS_sve_cntp}, HW_Category_SIMD, HW_Flag_Scalable|HW_Flag_BaseTypeFromFirstArg|HW_Flag_ExplicitMaskedOperation) HARDWARE_INTRINSIC(Sve, LeadingSignCount, -1, -1, false, {INS_sve_cls, INS_invalid, INS_sve_cls, INS_invalid, INS_sve_cls, INS_invalid, INS_sve_cls, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SIMD, HW_Flag_Scalable|HW_Flag_BaseTypeFromFirstArg|HW_Flag_EmbeddedMaskedOperation|HW_Flag_LowMaskedOperation) HARDWARE_INTRINSIC(Sve, LeadingZeroCount, -1, -1, false, {INS_sve_clz, INS_sve_clz, INS_sve_clz, INS_sve_clz, INS_sve_clz, INS_sve_clz, INS_sve_clz, INS_sve_clz, INS_invalid, INS_invalid}, HW_Category_SIMD, HW_Flag_Scalable|HW_Flag_BaseTypeFromFirstArg|HW_Flag_EmbeddedMaskedOperation|HW_Flag_LowMaskedOperation) 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..63cf86d37aa09a 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 @@ -1466,6 +1466,117 @@ internal Arm64() { } public static unsafe Vector FusedMultiplySubtractNegated(Vector minuend, Vector left, Vector right) { throw new PlatformNotSupportedException(); } + /// Unextended load + + /// + /// svfloat64_t svld1_gather_[s64]index[_f64](svbool_t pg, const float64_t *base, svint64_t indices) + /// LD1D Zresult.D, Pg/Z, [Xbase, Zindices.D, LSL #3] + /// + public static unsafe Vector GatherVector(Vector mask, double* address, Vector indices) { throw new PlatformNotSupportedException(); } + + /// + /// svfloat64_t svld1_gather[_u64base]_f64(svbool_t pg, svuint64_t bases) + /// LD1D Zresult.D, Pg/Z, [Zbases.D, #0] + /// + public static unsafe Vector GatherVector(Vector mask, Vector addresses) { throw new PlatformNotSupportedException(); } + + /// + /// svfloat64_t svld1_gather_[u64]index[_f64](svbool_t pg, const float64_t *base, svuint64_t indices) + /// LD1D Zresult.D, Pg/Z, [Xbase, Zindices.D, LSL #3] + /// + public static unsafe Vector GatherVector(Vector mask, double* address, Vector indices) { throw new PlatformNotSupportedException(); } + + /// + /// svint32_t svld1_gather_[s32]index[_s32](svbool_t pg, const int32_t *base, svint32_t indices) + /// LD1W Zresult.S, Pg/Z, [Xbase, Zindices.S, SXTW #2] + /// + public static unsafe Vector GatherVector(Vector mask, int* address, Vector indices) { throw new PlatformNotSupportedException(); } + + /// + /// svint32_t svld1_gather[_u32base]_s32(svbool_t pg, svuint32_t bases) + /// LD1W Zresult.S, Pg/Z, [Zbases.S, #0] + /// + public static unsafe Vector GatherVector(Vector mask, Vector addresses) { throw new PlatformNotSupportedException(); } + + /// + /// svint32_t svld1_gather_[u32]index[_s32](svbool_t pg, const int32_t *base, svuint32_t indices) + /// LD1W Zresult.S, Pg/Z, [Xbase, Zindices.S, UXTW #2] + /// + public static unsafe Vector GatherVector(Vector mask, int* address, Vector indices) { throw new PlatformNotSupportedException(); } + + /// + /// svint64_t svld1_gather_[s64]index[_s64](svbool_t pg, const int64_t *base, svint64_t indices) + /// LD1D Zresult.D, Pg/Z, [Xbase, Zindices.D, LSL #3] + /// + public static unsafe Vector GatherVector(Vector mask, long* address, Vector indices) { throw new PlatformNotSupportedException(); } + + /// + /// svint64_t svld1_gather[_u64base]_s64(svbool_t pg, svuint64_t bases) + /// LD1D Zresult.D, Pg/Z, [Zbases.D, #0] + /// + public static unsafe Vector GatherVector(Vector mask, Vector addresses) { throw new PlatformNotSupportedException(); } + + /// + /// svint64_t svld1_gather_[u64]index[_s64](svbool_t pg, const int64_t *base, svuint64_t indices) + /// LD1D Zresult.D, Pg/Z, [Xbase, Zindices.D, LSL #3] + /// + public static unsafe Vector GatherVector(Vector mask, long* address, Vector indices) { throw new PlatformNotSupportedException(); } + + /// + /// svfloat32_t svld1_gather_[s32]index[_f32](svbool_t pg, const float32_t *base, svint32_t indices) + /// LD1W Zresult.S, Pg/Z, [Xbase, Zindices.S, SXTW #2] + /// + public static unsafe Vector GatherVector(Vector mask, float* address, Vector indices) { throw new PlatformNotSupportedException(); } + + /// + /// svfloat32_t svld1_gather[_u32base]_f32(svbool_t pg, svuint32_t bases) + /// LD1W Zresult.S, Pg/Z, [Zbases.S, #0] + /// + public static unsafe Vector GatherVector(Vector mask, Vector addresses) { throw new PlatformNotSupportedException(); } + + /// + /// svfloat32_t svld1_gather_[u32]index[_f32](svbool_t pg, const float32_t *base, svuint32_t indices) + /// LD1W Zresult.S, Pg/Z, [Xbase, Zindices.S, UXTW #2] + /// + public static unsafe Vector GatherVector(Vector mask, float* address, Vector indices) { throw new PlatformNotSupportedException(); } + + /// + /// svuint32_t svld1_gather_[s32]index[_u32](svbool_t pg, const uint32_t *base, svint32_t indices) + /// LD1W Zresult.S, Pg/Z, [Xbase, Zindices.S, SXTW #2] + /// + public static unsafe Vector GatherVector(Vector mask, uint* address, Vector indices) { throw new PlatformNotSupportedException(); } + + /// + /// svuint32_t svld1_gather[_u32base]_u32(svbool_t pg, svuint32_t bases) + /// LD1W Zresult.S, Pg/Z, [Zbases.S, #0] + /// + public static unsafe Vector GatherVector(Vector mask, Vector addresses) { throw new PlatformNotSupportedException(); } + + /// + /// svuint32_t svld1_gather_[u32]index[_u32](svbool_t pg, const uint32_t *base, svuint32_t indices) + /// LD1W Zresult.S, Pg/Z, [Xbase, Zindices.S, UXTW #2] + /// + public static unsafe Vector GatherVector(Vector mask, uint* address, Vector indices) { throw new PlatformNotSupportedException(); } + + /// + /// svuint64_t svld1_gather_[s64]index[_u64](svbool_t pg, const uint64_t *base, svint64_t indices) + /// LD1D Zresult.D, Pg/Z, [Xbase, Zindices.D, LSL #3] + /// + public static unsafe Vector GatherVector(Vector mask, ulong* address, Vector indices) { throw new PlatformNotSupportedException(); } + + /// + /// svuint64_t svld1_gather[_u64base]_u64(svbool_t pg, svuint64_t bases) + /// LD1D Zresult.D, Pg/Z, [Zbases.D, #0] + /// + public static unsafe Vector GatherVector(Vector mask, Vector addresses) { throw new PlatformNotSupportedException(); } + + /// + /// svuint64_t svld1_gather_[u64]index[_u64](svbool_t pg, const uint64_t *base, svuint64_t indices) + /// LD1D Zresult.D, Pg/Z, [Xbase, Zindices.D, LSL #3] + /// + public static unsafe Vector GatherVector(Vector mask, ulong* address, Vector indices) { throw new PlatformNotSupportedException(); } + + /// Count set predicate bits /// 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..28e841d2fd382d 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 @@ -1522,6 +1522,117 @@ internal Arm64() { } public static unsafe Vector FusedMultiplySubtractNegated(Vector minuend, Vector left, Vector right) => FusedMultiplySubtractNegated(minuend, left, right); + /// Unextended load + + /// + /// svfloat64_t svld1_gather_[s64]index[_f64](svbool_t pg, const float64_t *base, svint64_t indices) + /// LD1D Zresult.D, Pg/Z, [Xbase, Zindices.D, LSL #3] + /// + public static unsafe Vector GatherVector(Vector mask, double* address, Vector indices) => GatherVector(mask, address, indices); + + /// + /// svfloat64_t svld1_gather[_u64base]_f64(svbool_t pg, svuint64_t bases) + /// LD1D Zresult.D, Pg/Z, [Zbases.D, #0] + /// + public static unsafe Vector GatherVector(Vector mask, Vector addresses) => GatherVector(mask, addresses); + + /// + /// svfloat64_t svld1_gather_[u64]index[_f64](svbool_t pg, const float64_t *base, svuint64_t indices) + /// LD1D Zresult.D, Pg/Z, [Xbase, Zindices.D, LSL #3] + /// + public static unsafe Vector GatherVector(Vector mask, double* address, Vector indices) => GatherVector(mask, address, indices); + + /// + /// svint32_t svld1_gather_[s32]index[_s32](svbool_t pg, const int32_t *base, svint32_t indices) + /// LD1W Zresult.S, Pg/Z, [Xbase, Zindices.S, SXTW #2] + /// + public static unsafe Vector GatherVector(Vector mask, int* address, Vector indices) => GatherVector(mask, address, indices); + + /// + /// svint32_t svld1_gather[_u32base]_s32(svbool_t pg, svuint32_t bases) + /// LD1W Zresult.S, Pg/Z, [Zbases.S, #0] + /// + public static unsafe Vector GatherVector(Vector mask, Vector addresses) => GatherVector(mask, addresses); + + /// + /// svint32_t svld1_gather_[u32]index[_s32](svbool_t pg, const int32_t *base, svuint32_t indices) + /// LD1W Zresult.S, Pg/Z, [Xbase, Zindices.S, UXTW #2] + /// + public static unsafe Vector GatherVector(Vector mask, int* address, Vector indices) => GatherVector(mask, address, indices); + + /// + /// svint64_t svld1_gather_[s64]index[_s64](svbool_t pg, const int64_t *base, svint64_t indices) + /// LD1D Zresult.D, Pg/Z, [Xbase, Zindices.D, LSL #3] + /// + public static unsafe Vector GatherVector(Vector mask, long* address, Vector indices) => GatherVector(mask, address, indices); + + /// + /// svint64_t svld1_gather[_u64base]_s64(svbool_t pg, svuint64_t bases) + /// LD1D Zresult.D, Pg/Z, [Zbases.D, #0] + /// + public static unsafe Vector GatherVector(Vector mask, Vector addresses) => GatherVector(mask, addresses); + + /// + /// svint64_t svld1_gather_[u64]index[_s64](svbool_t pg, const int64_t *base, svuint64_t indices) + /// LD1D Zresult.D, Pg/Z, [Xbase, Zindices.D, LSL #3] + /// + public static unsafe Vector GatherVector(Vector mask, long* address, Vector indices) => GatherVector(mask, address, indices); + + /// + /// svfloat32_t svld1_gather_[s32]index[_f32](svbool_t pg, const float32_t *base, svint32_t indices) + /// LD1W Zresult.S, Pg/Z, [Xbase, Zindices.S, SXTW #2] + /// + public static unsafe Vector GatherVector(Vector mask, float* address, Vector indices) => GatherVector(mask, address, indices); + + /// + /// svfloat32_t svld1_gather[_u32base]_f32(svbool_t pg, svuint32_t bases) + /// LD1W Zresult.S, Pg/Z, [Zbases.S, #0] + /// + public static unsafe Vector GatherVector(Vector mask, Vector addresses) => GatherVector(mask, addresses); + + /// + /// svfloat32_t svld1_gather_[u32]index[_f32](svbool_t pg, const float32_t *base, svuint32_t indices) + /// LD1W Zresult.S, Pg/Z, [Xbase, Zindices.S, UXTW #2] + /// + public static unsafe Vector GatherVector(Vector mask, float* address, Vector indices) => GatherVector(mask, address, indices); + + /// + /// svuint32_t svld1_gather_[s32]index[_u32](svbool_t pg, const uint32_t *base, svint32_t indices) + /// LD1W Zresult.S, Pg/Z, [Xbase, Zindices.S, SXTW #2] + /// + public static unsafe Vector GatherVector(Vector mask, uint* address, Vector indices) => GatherVector(mask, address, indices); + + /// + /// svuint32_t svld1_gather[_u32base]_u32(svbool_t pg, svuint32_t bases) + /// LD1W Zresult.S, Pg/Z, [Zbases.S, #0] + /// + public static unsafe Vector GatherVector(Vector mask, Vector addresses) => GatherVector(mask, addresses); + + /// + /// svuint32_t svld1_gather_[u32]index[_u32](svbool_t pg, const uint32_t *base, svuint32_t indices) + /// LD1W Zresult.S, Pg/Z, [Xbase, Zindices.S, UXTW #2] + /// + public static unsafe Vector GatherVector(Vector mask, uint* address, Vector indices) => GatherVector(mask, address, indices); + + /// + /// svuint64_t svld1_gather_[s64]index[_u64](svbool_t pg, const uint64_t *base, svint64_t indices) + /// LD1D Zresult.D, Pg/Z, [Xbase, Zindices.D, LSL #3] + /// + public static unsafe Vector GatherVector(Vector mask, ulong* address, Vector indices) => GatherVector(mask, address, indices); + + /// + /// svuint64_t svld1_gather[_u64base]_u64(svbool_t pg, svuint64_t bases) + /// LD1D Zresult.D, Pg/Z, [Zbases.D, #0] + /// + public static unsafe Vector GatherVector(Vector mask, Vector addresses) => GatherVector(mask, addresses); + + /// + /// svuint64_t svld1_gather_[u64]index[_u64](svbool_t pg, const uint64_t *base, svuint64_t indices) + /// LD1D Zresult.D, Pg/Z, [Xbase, Zindices.D, LSL #3] + /// + public static unsafe Vector GatherVector(Vector mask, ulong* address, Vector indices) => GatherVector(mask, address, indices); + + /// Count set predicate bits /// 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 7ed0b7d273a3f9..5620d8f10094cc 100644 --- a/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs +++ b/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs @@ -4391,6 +4391,25 @@ internal Arm64() { } public static System.Numerics.Vector FusedMultiplySubtractNegated(System.Numerics.Vector minuend, System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } public static System.Numerics.Vector FusedMultiplySubtractNegated(System.Numerics.Vector minuend, System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } + public static unsafe System.Numerics.Vector GatherVector(System.Numerics.Vector mask, double* address, System.Numerics.Vector indices) { throw null; } + public static System.Numerics.Vector GatherVector(System.Numerics.Vector mask, System.Numerics.Vector addresses) { throw null; } + public static unsafe System.Numerics.Vector GatherVector(System.Numerics.Vector mask, double* address, System.Numerics.Vector indices) { throw null; } + public static unsafe System.Numerics.Vector GatherVector(System.Numerics.Vector mask, int* address, System.Numerics.Vector indices) { throw null; } + public static System.Numerics.Vector GatherVector(System.Numerics.Vector mask, System.Numerics.Vector addresses) { throw null; } + public static unsafe System.Numerics.Vector GatherVector(System.Numerics.Vector mask, int* address, System.Numerics.Vector indices) { throw null; } + public static unsafe System.Numerics.Vector GatherVector(System.Numerics.Vector mask, long* address, System.Numerics.Vector indices) { throw null; } + public static System.Numerics.Vector GatherVector(System.Numerics.Vector mask, System.Numerics.Vector addresses) { throw null; } + public static unsafe System.Numerics.Vector GatherVector(System.Numerics.Vector mask, long* address, System.Numerics.Vector indices) { throw null; } + public static unsafe System.Numerics.Vector GatherVector(System.Numerics.Vector mask, float* address, System.Numerics.Vector indices) { throw null; } + public static System.Numerics.Vector GatherVector(System.Numerics.Vector mask, System.Numerics.Vector addresses) { throw null; } + public static unsafe System.Numerics.Vector GatherVector(System.Numerics.Vector mask, float* address, System.Numerics.Vector indices) { throw null; } + public static unsafe System.Numerics.Vector GatherVector(System.Numerics.Vector mask, uint* address, System.Numerics.Vector indices) { throw null; } + public static System.Numerics.Vector GatherVector(System.Numerics.Vector mask, System.Numerics.Vector addresses) { throw null; } + public static unsafe System.Numerics.Vector GatherVector(System.Numerics.Vector mask, uint* address, System.Numerics.Vector indices) { throw null; } + public static unsafe System.Numerics.Vector GatherVector(System.Numerics.Vector mask, ulong* address, System.Numerics.Vector indices) { throw null; } + public static System.Numerics.Vector GatherVector(System.Numerics.Vector mask, System.Numerics.Vector addresses) { throw null; } + public static unsafe System.Numerics.Vector GatherVector(System.Numerics.Vector mask, ulong* address, System.Numerics.Vector indices) { throw null; } + public static ulong GetActiveElementCount(System.Numerics.Vector mask, System.Numerics.Vector from) { throw null; } public static ulong GetActiveElementCount(System.Numerics.Vector mask, System.Numerics.Vector from) { throw null; } public static ulong GetActiveElementCount(System.Numerics.Vector mask, System.Numerics.Vector from) { throw null; } diff --git a/src/tests/Common/GenerateHWIntrinsicTests/GenerateHWIntrinsicTests_Arm.cs b/src/tests/Common/GenerateHWIntrinsicTests/GenerateHWIntrinsicTests_Arm.cs index e1a3d2294618db..57b08a8fd48a88 100644 --- a/src/tests/Common/GenerateHWIntrinsicTests/GenerateHWIntrinsicTests_Arm.cs +++ b/src/tests/Common/GenerateHWIntrinsicTests/GenerateHWIntrinsicTests_Arm.cs @@ -3162,6 +3162,26 @@ ("SveCreateTrueMaskTest.template", new Dictionary { ["TestName"] = "Sve_CreateTrueMaskUInt32", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "CreateTrueMaskUInt32", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt32", ["Op1Type"] = "SveMaskPattern"}), ("SveCreateTrueMaskTest.template", new Dictionary { ["TestName"] = "Sve_CreateTrueMaskUInt64", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "CreateTrueMaskUInt64", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt64", ["Op1Type"] = "SveMaskPattern"}), + // ("SveGatherVectorVectorBases.template", new Dictionary { ["TestName"] = "Sve_GatherVector_Bases_float_uint", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "GatherVector", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["NextValueBase"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "result[i] != (firstOp[i] == 0 ? 0 : *(Single*)(secondOp[i]))",}), + // ("SveGatherVectorVectorBases.template", new Dictionary { ["TestName"] = "Sve_GatherVector_Bases_int_uint", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "GatherVector", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["NextValueBase"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "result[i] != (firstOp[i] == 0 ? 0 : *(Int32*)(secondOp[i]))",}), + // ("SveGatherVectorVectorBases.template", new Dictionary { ["TestName"] = "Sve_GatherVector_Bases_uint_uint", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "GatherVector", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["NextValueBase"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "result[i] != (firstOp[i] == 0 ? 0 : *(UInt32*)(secondOp[i]))",}), + ("SveGatherVectorVectorBases.template", new Dictionary { ["TestName"] = "Sve_GatherVector_Bases_double_ulong", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "GatherVector", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["NextValueBase"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "result[i] != (firstOp[i] == 0 ? 0 : *(Double*)(secondOp[i]))",}), + ("SveGatherVectorVectorBases.template", new Dictionary { ["TestName"] = "Sve_GatherVector_Bases_long_ulong", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "GatherVector", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["NextValueBase"] = "TestLibrary.Generator.GetInt64()", ["ValidateIterResult"] = "result[i] != (firstOp[i] == 0 ? 0 : *(Int64*)(secondOp[i]))",}), + ("SveGatherVectorVectorBases.template", new Dictionary { ["TestName"] = "Sve_GatherVector_Bases_ulong_ulong", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "GatherVector", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["NextValueBase"] = "TestLibrary.Generator.GetUInt64()", ["ValidateIterResult"] = "result[i] != (firstOp[i] == 0 ? 0 : *(UInt64*)(secondOp[i]))",}), + + ("SveGatherVectorIndices.template", new Dictionary { ["TestName"] = "Sve_GatherVector_Indices_float_int", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "GatherVector", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Single", ["Op2BaseType"] = "Single", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "Int32", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "result[i] != (firstOp[i] == 0 ? 0 : secondOp[thirdOp[i]])",}), + ("SveGatherVectorIndices.template", new Dictionary { ["TestName"] = "Sve_GatherVector_Indices_int_int", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "GatherVector", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int32", ["Op2BaseType"] = "Int32", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "Int32", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "result[i] != (firstOp[i] == 0 ? 0 : secondOp[thirdOp[i]])",}), + ("SveGatherVectorIndices.template", new Dictionary { ["TestName"] = "Sve_GatherVector_Indices_uint_int", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "GatherVector", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt32", ["Op2BaseType"] = "UInt32", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "Int32", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "result[i] != (firstOp[i] == 0 ? 0 : secondOp[thirdOp[i]])",}), + ("SveGatherVectorIndices.template", new Dictionary { ["TestName"] = "Sve_GatherVector_Indices_float_uint", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "GatherVector", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Single", ["Op2BaseType"] = "Single", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "UInt32", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "result[i] != (firstOp[i] == 0 ? 0 : secondOp[thirdOp[i]])",}), + ("SveGatherVectorIndices.template", new Dictionary { ["TestName"] = "Sve_GatherVector_Indices_int_uint", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "GatherVector", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int32", ["Op2BaseType"] = "Int32", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "UInt32", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "result[i] != (firstOp[i] == 0 ? 0 : secondOp[thirdOp[i]])",}), + ("SveGatherVectorIndices.template", new Dictionary { ["TestName"] = "Sve_GatherVector_Indices_uint_uint", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "GatherVector", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt32", ["Op2BaseType"] = "UInt32", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "UInt32", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "result[i] != (firstOp[i] == 0 ? 0 : secondOp[thirdOp[i]])",}), + ("SveGatherVectorIndices.template", new Dictionary { ["TestName"] = "Sve_GatherVector_Indices_double_long", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "GatherVector", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Double", ["Op2BaseType"] = "Double", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "Int64", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt64()", ["ValidateIterResult"] = "result[i] != (firstOp[i] == 0 ? 0 : secondOp[thirdOp[i]])",}), + ("SveGatherVectorIndices.template", new Dictionary { ["TestName"] = "Sve_GatherVector_Indices_long_long", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "GatherVector", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int64", ["Op2BaseType"] = "Int64", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "Int64", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt64()", ["ValidateIterResult"] = "result[i] != (firstOp[i] == 0 ? 0 : secondOp[thirdOp[i]])",}), + ("SveGatherVectorIndices.template", new Dictionary { ["TestName"] = "Sve_GatherVector_Indices_ulong_long", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "GatherVector", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt64", ["Op2BaseType"] = "UInt64", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "Int64", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt64()", ["ValidateIterResult"] = "result[i] != (firstOp[i] == 0 ? 0 : secondOp[thirdOp[i]])",}), + ("SveGatherVectorIndices.template", new Dictionary { ["TestName"] = "Sve_GatherVector_Indices_double_ulong", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "GatherVector", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Double", ["Op2BaseType"] = "Double", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "UInt64", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt64()", ["ValidateIterResult"] = "result[i] != (firstOp[i] == 0 ? 0 : secondOp[thirdOp[i]])",}), + ("SveGatherVectorIndices.template", new Dictionary { ["TestName"] = "Sve_GatherVector_Indices_long_ulong", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "GatherVector", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int64", ["Op2BaseType"] = "Int64", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "UInt64", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt64()", ["ValidateIterResult"] = "result[i] != (firstOp[i] == 0 ? 0 : secondOp[thirdOp[i]])",}), + ("SveGatherVectorIndices.template", new Dictionary { ["TestName"] = "Sve_GatherVector_Indices_ulong_ulong", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "GatherVector", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt64", ["Op2BaseType"] = "UInt64", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "UInt64", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt64()", ["ValidateIterResult"] = "result[i] != (firstOp[i] == 0 ? 0 : secondOp[thirdOp[i]])",}), + ("SveVecReduceToScalarBinOpTest.template", new Dictionary { ["TestName"] = "Sve_GetActiveElementCount_byte", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "GetActiveElementCount", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskByte()", ["NextValueOp2"] = "Helpers.getMaskByte()", ["ValidateResult"] = "if (Helpers.MaskBothSet(left, right) != result) succeeded = false;",}), ("SveVecReduceToScalarBinOpTest.template", new Dictionary { ["TestName"] = "Sve_GetActiveElementCount_sbyte", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "GetActiveElementCount", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskSByte()", ["NextValueOp2"] = "Helpers.getMaskSByte()", ["ValidateResult"] = "if (Helpers.MaskBothSet(left, right) != result) succeeded = false;",}), ("SveVecReduceToScalarBinOpTest.template", new Dictionary { ["TestName"] = "Sve_GetActiveElementCount_short", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "GetActiveElementCount", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskInt16()", ["NextValueOp2"] = "Helpers.getMaskInt16()", ["ValidateResult"] = "if (Helpers.MaskBothSet(left, right) != result) succeeded = false;",}), diff --git a/src/tests/JIT/HardwareIntrinsics/Arm/Shared/SveGatherVectorIndices.template b/src/tests/JIT/HardwareIntrinsics/Arm/Shared/SveGatherVectorIndices.template new file mode 100644 index 00000000000000..93b406210b15a4 --- /dev/null +++ b/src/tests/JIT/HardwareIntrinsics/Arm/Shared/SveGatherVectorIndices.template @@ -0,0 +1,363 @@ +// 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.Reflection; +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 SveGatherVectorVectorBasesTest__{TestName}(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + // Validates basic functionality works + 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(); + } + 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 SveGatherVectorVectorBasesTest__{TestName} + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] inArray3; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle inHandle3; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable({Op1BaseType}[] inArray1, {Op2BaseType}[] inArray2, {Op3BaseType}[] inArray3, {RetBaseType}[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf<{Op1BaseType}>(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf<{Op2BaseType}>(); + int sizeOfinArray3 = inArray3.Length * Unsafe.SizeOf<{Op3BaseType}>(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf<{RetBaseType}>(); + + if ((alignment != 64 && alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray3 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException($"Invalid value of alignment: {alignment}, sizeOfinArray1: {sizeOfinArray1}, sizeOfinArray2: {sizeOfinArray2}, sizeOfinArray3: {sizeOfinArray3}, sizeOfoutArray: {sizeOfoutArray}"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment + sizeOfinArray2]; + this.inArray3 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.inHandle3 = GCHandle.Alloc(this.inArray3, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As<{Op1BaseType}, byte>(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As<{Op2BaseType}, byte>(ref inArray2[0]), (uint)sizeOfinArray2); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray3Ptr), ref Unsafe.As<{Op3BaseType}, byte>(ref inArray3[0]), (uint)sizeOfinArray3); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray3Ptr => Align((byte*)(inHandle3.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + inHandle3.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}> _fld1; + public {Op2BaseType}* _fld2; + public {Op3VectorType}<{Op3BaseType}> _fld3; + + public static TestStruct Create(DataTable _dataTable) + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = {NextValueOp1}; } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = {NextValueOp2}; } + + // Ensure all values of _data3 fit within the number of _data2 elements + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = {NextValueOp3} % ({Op3BaseType})Op2ElementCount; } + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{Op1VectorType}<{Op1BaseType}>, byte>(ref testStruct._fld1), ref Unsafe.As<{Op1BaseType}, byte>(ref _data1[0]), (uint)Unsafe.SizeOf<{Op1VectorType}<{Op1BaseType}>>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{Op3VectorType}<{Op3BaseType}>, byte>(ref testStruct._fld3), ref Unsafe.As<{Op3BaseType}, byte>(ref _data3[0]), (uint)Unsafe.SizeOf<{Op3VectorType}<{Op3BaseType}>>()); + + testStruct._fld2 = ({Op2BaseType}*)_dataTable.inArray2Ptr; + + return testStruct; + } + + public void RunStructFldScenario(SveGatherVectorVectorBasesTest__{TestName} testClass) + { + var result = {Isa}.{Method}(_fld1, _fld2, _fld3); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + } + + private static readonly int LargestVectorSize = {LargestVectorSize}; + + // A large enough buffer to hold many values. Op3 will index into Op2. + private static readonly int Op2ElementCount = 1024; + + private static readonly int Op1ElementCount = Unsafe.SizeOf<{Op1VectorType}<{Op1BaseType}>>() / sizeof({Op1BaseType}); + private static readonly int Op3ElementCount = Unsafe.SizeOf<{Op3VectorType}<{Op3BaseType}>>() / sizeof({Op3BaseType}); + private static readonly int RetElementCount = Unsafe.SizeOf<{RetVectorType}<{RetBaseType}>>() / sizeof({RetBaseType}); + + private static {Op1BaseType}[] _data1 = new {Op1BaseType}[Op1ElementCount]; + private static {Op2BaseType}[] _data2 = new {Op2BaseType}[Op2ElementCount]; + private static {Op3BaseType}[] _data3 = new {Op3BaseType}[Op3ElementCount]; + + private {Op1VectorType}<{Op1BaseType}> _fld1; + private {Op2BaseType}* _fld2; + private {Op3VectorType}<{Op3BaseType}> _fld3; + + private DataTable _dataTable; + + public SveGatherVectorVectorBasesTest__{TestName}() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = {NextValueOp1}; } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = {NextValueOp2}; } + + // Ensure all values of _data3 fit within the number of _data2 elements + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = {NextValueOp3} % ({Op3BaseType})Op2ElementCount; } + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{Op1VectorType}<{Op1BaseType}>, byte>(ref _fld1), ref Unsafe.As<{Op1BaseType}, byte>(ref _data1[0]), (uint)Unsafe.SizeOf<{Op1VectorType}<{Op1BaseType}>>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{Op3VectorType}<{Op3BaseType}>, byte>(ref _fld3), ref Unsafe.As<{Op3BaseType}, byte>(ref _data3[0]), (uint)Unsafe.SizeOf<{Op3VectorType}<{Op3BaseType}>>()); + + _dataTable = new DataTable(_data1, _data2, _data3, new {RetBaseType}[RetElementCount], LargestVectorSize); + + _fld2 = ({Op2BaseType}*)_dataTable.inArray2Ptr; + } + + 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.inArray1Ptr), + ({Op2BaseType}*)_dataTable.inArray2Ptr, + Unsafe.Read<{Op3VectorType}<{Op3BaseType}>>(_dataTable.inArray3Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + {Op1VectorType}<{Op1BaseType}> loadMask1 = Sve.CreateTrueMask{Op1BaseType}(SveMaskPattern.All); + {Op3VectorType}<{Op3BaseType}> loadMask3 = Sve.CreateTrueMask{Op3BaseType}(SveMaskPattern.All); + + var result = {Isa}.{Method}( + {LoadIsa}.Load{Op1VectorType}(loadMask1, ({Op1BaseType}*)(_dataTable.inArray1Ptr)), + ({Op2BaseType}*)_dataTable.inArray2Ptr, + {LoadIsa}.Load{Op3VectorType}(loadMask3, ({Op3BaseType}*)(_dataTable.inArray3Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _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({Op2BaseType}*), typeof({Op3VectorType}<{Op3BaseType}>) }) + .Invoke(null, new object[] { + Unsafe.Read<{Op1VectorType}<{Op1BaseType}>>(_dataTable.inArray1Ptr), + Pointer.Box(_dataTable.inArray2Ptr, typeof({Op2BaseType}*)), + Unsafe.Read<{Op3VectorType}<{Op3BaseType}>>(_dataTable.inArray3Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, ({RetVectorType}<{RetBaseType}>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read<{Op1VectorType}<{Op1BaseType}>>(_dataTable.inArray1Ptr); + var op2 = ({Op2BaseType}*)_dataTable.inArray2Ptr; + var op3 = Unsafe.Read<{Op3VectorType}<{Op3BaseType}>>(_dataTable.inArray3Ptr); + var result = {Isa}.{Method}(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = {Isa}.{Method}(_fld1, _fld2, _fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(_dataTable); + var result = {Isa}.{Method}(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(_dataTable); + test.RunStructFldScenario(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + Succeeded = false; + + try + { + RunBasicScenario_Load(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult({Op1VectorType}<{Op1BaseType}> op1, {Op2BaseType}* op2, {Op3VectorType}<{Op3BaseType}> op3, void* result, [CallerMemberName] string method = "") + { + {Op1BaseType}[] inArray1 = new {Op1BaseType}[Op1ElementCount]; + {Op2BaseType}[] inArray2 = new {Op2BaseType}[Op2ElementCount]; + {Op3BaseType}[] inArray3 = new {Op3BaseType}[Op3ElementCount]; + {RetBaseType}[] outArray = new {RetBaseType}[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As<{Op1BaseType}, byte>(ref inArray1[0]), op1); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{Op2BaseType}, byte>(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)(Unsafe.SizeOf<{Op2BaseType}>() * Op2ElementCount)); + Unsafe.WriteUnaligned(ref Unsafe.As<{Op3BaseType}, byte>(ref inArray3[0]), op3); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{RetBaseType}, byte>(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf<{RetVectorType}<{RetBaseType}>>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(void* firstOp, void* secondOp, void* thirdOp, void* result, [CallerMemberName] string method = "") + { + {Op1BaseType}[] inArray1 = new {Op1BaseType}[Op1ElementCount]; + {Op2BaseType}[] inArray2 = new {Op2BaseType}[Op2ElementCount]; + {Op3BaseType}[] inArray3 = new {Op3BaseType}[Op3ElementCount]; + {RetBaseType}[] outArray = new {RetBaseType}[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{Op1BaseType}, byte>(ref inArray1[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf<{Op1VectorType}<{Op1BaseType}>>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{Op2BaseType}, byte>(ref inArray2[0]), ref Unsafe.AsRef(secondOp), (uint)(Unsafe.SizeOf<{Op2BaseType}>() * Op2ElementCount)); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{Op3BaseType}, byte>(ref inArray3[0]), ref Unsafe.AsRef(thirdOp), (uint)Unsafe.SizeOf<{Op3VectorType}<{Op3BaseType}>>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{RetBaseType}, byte>(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf<{RetVectorType}<{RetBaseType}>>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult({Op1BaseType}[] firstOp, {Op2BaseType}[] secondOp, {Op3BaseType}[] thirdOp, {RetBaseType}[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if ({ValidateIterResult}) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof({Isa})}.{nameof({Isa}.{Method})}<{RetBaseType}>({Op1BaseType}, {Op2BaseType}, {Op3BaseType}): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" thirdOp: ({string.Join(", ", thirdOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} \ No newline at end of file diff --git a/src/tests/JIT/HardwareIntrinsics/Arm/Shared/SveGatherVectorVectorBases.template b/src/tests/JIT/HardwareIntrinsics/Arm/Shared/SveGatherVectorVectorBases.template new file mode 100644 index 00000000000000..a9bc0a28f036db --- /dev/null +++ b/src/tests/JIT/HardwareIntrinsics/Arm/Shared/SveGatherVectorVectorBases.template @@ -0,0 +1,356 @@ +// 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.Reflection; +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 SveGatherVectorVectorBasesTest__{TestName}(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + // Validates basic functionality works + 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(); + } + 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 SveGatherVectorVectorBasesTest__{TestName} + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] baseArray; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle baseHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable({Op1BaseType}[] inArray1, {Op2BaseType}[] inArray2, {RetBaseType}[] baseArray, {RetBaseType}[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf<{Op1BaseType}>(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf<{Op2BaseType}>(); + int sizeOfBaseArray = baseArray.Length * Unsafe.SizeOf<{RetBaseType}>(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf<{RetBaseType}>(); + + if ((alignment != 64 && alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException($"Invalid value of alignment: {alignment}, sizeOfinArray1: {sizeOfinArray1}, sizeOfinArray2: {sizeOfinArray2}, sizeOfoutArray: {sizeOfoutArray}"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.baseArray = new byte[alignment + sizeOfBaseArray]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.baseHandle = GCHandle.Alloc(this.baseArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As<{Op1BaseType}, byte>(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(baseArrayPtr), ref Unsafe.As<{RetBaseType}, byte>(ref baseArray[0]), (uint)sizeOfBaseArray); + + // Add the base pointer to the offsets within inArray2 to create complete pointers. + for (var i = 0; i < inArray2.Length; i++) { inArray2[i] += ({Op2BaseType})baseArrayPtr; } + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As<{Op2BaseType}, byte>(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* baseArrayPtr => Align((byte*)(baseHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + baseHandle.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}> _fld1; + public {Op2VectorType}<{Op2BaseType}> _fld2; + + public static TestStruct Create(DataTable _dataTable) + { + var testStruct = new TestStruct(); + + for (var i = 0; i < BaseElementCount; i++) { _datab[i] = {NextValueBase}; } + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = {NextValueOp1}; } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = {NextValueOp2}; } + + // Fill full of offsets into the data buffer. + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = {NextValueOp2} % ({Op2BaseType})BaseElementCount; } + + // Add the base pointer to the offsets within inArray2 to create complete pointers. + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] += ({Op2BaseType})_dataTable.baseArrayPtr; } + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{Op1VectorType}<{Op1BaseType}>, byte>(ref testStruct._fld1), ref Unsafe.As<{Op1BaseType}, byte>(ref _data1[0]), (uint)Unsafe.SizeOf<{Op1VectorType}<{Op1BaseType}>>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{Op2VectorType}<{Op2BaseType}>, byte>(ref testStruct._fld2), ref Unsafe.As<{Op2BaseType}, byte>(ref _data2[0]), (uint)Unsafe.SizeOf<{Op2VectorType}<{Op2BaseType}>>()); + + return testStruct; + } + + public void RunStructFldScenario(SveGatherVectorVectorBasesTest__{TestName} testClass) + { + var result = {Isa}.{Method}(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + + private static readonly int LargestVectorSize = {LargestVectorSize}; + + // A large enough buffer to hold many values. + // Values in Op2 will point to locations within this buffer. + private static readonly int BaseElementCount = 1024; + private static {RetBaseType}[] _datab = new {RetBaseType}[BaseElementCount]; + + private static readonly int Op1ElementCount = Unsafe.SizeOf<{Op1VectorType}<{Op1BaseType}>>() / sizeof({Op1BaseType}); + private static readonly int Op2ElementCount = Unsafe.SizeOf<{Op2VectorType}<{Op2BaseType}>>() / sizeof({Op2BaseType}); + private static readonly int RetElementCount = Unsafe.SizeOf<{RetVectorType}<{RetBaseType}>>() / sizeof({RetBaseType}); + + private static {Op1BaseType}[] _data1 = new {Op1BaseType}[Op1ElementCount]; + private static {Op2BaseType}[] _data2 = new {Op2BaseType}[Op2ElementCount]; + + private {Op1VectorType}<{Op1BaseType}> _fld1; + private {Op2VectorType}<{Op2BaseType}> _fld2; + + private DataTable _dataTable; + + public SveGatherVectorVectorBasesTest__{TestName}() + { + Succeeded = true; + + for (var i = 0; i < BaseElementCount; i++) { _datab[i] = {NextValueBase}; } + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = {NextValueOp1}; } + + // Fill full of offsets into the data buffer. They wil be expanded to full pointers inside the DataTable constructor. + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = {NextValueOp2} % ({Op2BaseType})BaseElementCount; } + + _dataTable = new DataTable(_data1, _data2, _datab, new {RetBaseType}[RetElementCount], LargestVectorSize); + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{Op1VectorType}<{Op1BaseType}>, byte>(ref _fld1), ref Unsafe.As<{Op1BaseType}, byte>(ref _data1[0]), (uint)Unsafe.SizeOf<{Op1VectorType}<{Op1BaseType}>>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{Op2VectorType}<{Op2BaseType}>, byte>(ref _fld2), ref Unsafe.As<{Op2BaseType}, byte>(ref _data2[0]), (uint)Unsafe.SizeOf<{Op2VectorType}<{Op2BaseType}>>()); + } + + 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.inArray1Ptr), + Unsafe.Read<{Op2VectorType}<{Op2BaseType}>>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + {Op1VectorType}<{Op1BaseType}> loadMask1 = Sve.CreateTrueMask{Op1BaseType}(SveMaskPattern.All); + {Op2VectorType}<{Op2BaseType}> loadMask2 = Sve.CreateTrueMask{Op2BaseType}(SveMaskPattern.All); + + var result = {Isa}.{Method}( + {LoadIsa}.Load{Op1VectorType}(loadMask1, ({Op1BaseType}*)(_dataTable.inArray1Ptr)), + {LoadIsa}.Load{Op2VectorType}(loadMask2, ({Op2BaseType}*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _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({Op1VectorType}<{Op2BaseType}>) }) + .Invoke(null, new object[] { + Unsafe.Read<{Op1VectorType}<{Op1BaseType}>>(_dataTable.inArray1Ptr), + Unsafe.Read<{Op2VectorType}<{Op2BaseType}>>(_dataTable.inArray2Ptr), + }); + + Unsafe.Write(_dataTable.outArrayPtr, ({RetVectorType}<{RetBaseType}>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read<{Op1VectorType}<{Op1BaseType}>>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read<{Op2VectorType}<{Op2BaseType}>>(_dataTable.inArray2Ptr); + var result = {Isa}.{Method}(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = {Isa}.{Method}(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(_dataTable); + var result = {Isa}.{Method}(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(_dataTable); + test.RunStructFldScenario(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + Succeeded = false; + + try + { + RunBasicScenario_Load(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult({Op1VectorType}<{Op1BaseType}> op1, {Op2VectorType}<{Op2BaseType}> op2, void* result, [CallerMemberName] string method = "") + { + {Op1BaseType}[] inArray1 = new {Op1BaseType}[Op1ElementCount]; + {Op2BaseType}[] inArray2 = new {Op2BaseType}[Op2ElementCount]; + {RetBaseType}[] outArray = new {RetBaseType}[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As<{Op1BaseType}, byte>(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As<{Op2BaseType}, byte>(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{RetBaseType}, byte>(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf<{RetVectorType}<{RetBaseType}>>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* firstOp, void* secondOp, void* result, [CallerMemberName] string method = "") + { + {Op1BaseType}[] inArray1 = new {Op1BaseType}[Op1ElementCount]; + {Op2BaseType}[] inArray2 = new {Op2BaseType}[Op2ElementCount]; + {RetBaseType}[] outArray = new {RetBaseType}[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{Op1BaseType}, byte>(ref inArray1[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf<{Op1VectorType}<{Op1BaseType}>>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{Op2BaseType}, byte>(ref inArray2[0]), ref Unsafe.AsRef(secondOp), (uint)(Unsafe.SizeOf<{Op2VectorType}<{Op2BaseType}>>())); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{RetBaseType}, byte>(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf<{RetVectorType}<{RetBaseType}>>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult({Op1BaseType}[] firstOp, {Op2BaseType}[] secondOp, {RetBaseType}[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if ({ValidateIterResult}) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof({Isa})}.{nameof({Isa}.{Method})}<{RetBaseType}>({Op1BaseType}, {Op2BaseType}, {Op2BaseType}): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} \ No newline at end of file