diff --git a/src/coreclr/jit/codegenarm64test.cpp b/src/coreclr/jit/codegenarm64test.cpp
index 52633ed6733e6..2057a72323bf7 100644
--- a/src/coreclr/jit/codegenarm64test.cpp
+++ b/src/coreclr/jit/codegenarm64test.cpp
@@ -5314,11 +5314,11 @@ void CodeGen::genArm64EmitterUnitTestsSve()
#endif // ALL_ARM64_EMITTER_UNIT_TESTS_SVE_UNSUPPORTED
// IF_SVE_AI_3A
- theEmitter->emitIns_R_R_R(INS_sve_saddv, EA_1BYTE, REG_V1, REG_P4, REG_V2,
+ theEmitter->emitIns_R_R_R(INS_sve_saddv, EA_SCALABLE, REG_V1, REG_P4, REG_V2,
INS_OPTS_SCALABLE_B); // SADDV
, , .
- theEmitter->emitIns_R_R_R(INS_sve_saddv, EA_2BYTE, REG_V2, REG_P5, REG_V3,
+ theEmitter->emitIns_R_R_R(INS_sve_saddv, EA_SCALABLE, REG_V2, REG_P5, REG_V3,
INS_OPTS_SCALABLE_H); // SADDV , , .
- theEmitter->emitIns_R_R_R(INS_sve_uaddv, EA_4BYTE, REG_V3, REG_P6, REG_V4,
+ theEmitter->emitIns_R_R_R(INS_sve_uaddv, EA_SCALABLE, REG_V3, REG_P6, REG_V4,
INS_OPTS_SCALABLE_S); // UADDV , , .
// IF_SVE_AJ_3A
@@ -6768,15 +6768,15 @@ void CodeGen::genArm64EmitterUnitTestsSve()
#endif // ALL_ARM64_EMITTER_UNIT_TESTS_SVE_UNSUPPORTED
// IF_SVE_HE_3A
- theEmitter->emitIns_R_R_R(INS_sve_faddv, EA_2BYTE, REG_V21, REG_P7, REG_V7,
+ theEmitter->emitIns_R_R_R(INS_sve_faddv, EA_SCALABLE, REG_V21, REG_P7, REG_V7,
INS_OPTS_SCALABLE_H); // FADDV , , .
- theEmitter->emitIns_R_R_R(INS_sve_fmaxnmv, EA_2BYTE, REG_V22, REG_P6, REG_V6,
+ theEmitter->emitIns_R_R_R(INS_sve_fmaxnmv, EA_SCALABLE, REG_V22, REG_P6, REG_V6,
INS_OPTS_SCALABLE_H); // FMAXNMV , , .
- theEmitter->emitIns_R_R_R(INS_sve_fmaxv, EA_4BYTE, REG_V23, REG_P5, REG_V5,
+ theEmitter->emitIns_R_R_R(INS_sve_fmaxv, EA_SCALABLE, REG_V23, REG_P5, REG_V5,
INS_OPTS_SCALABLE_S); // FMAXV , , .
- theEmitter->emitIns_R_R_R(INS_sve_fminnmv, EA_8BYTE, REG_V24, REG_P4, REG_V4,
+ theEmitter->emitIns_R_R_R(INS_sve_fminnmv, EA_SCALABLE, REG_V24, REG_P4, REG_V4,
INS_OPTS_SCALABLE_D); // FMINNMV , , .
- theEmitter->emitIns_R_R_R(INS_sve_fminv, EA_4BYTE, REG_V25, REG_P3, REG_V3,
+ theEmitter->emitIns_R_R_R(INS_sve_fminv, EA_SCALABLE, REG_V25, REG_P3, REG_V3,
INS_OPTS_SCALABLE_S); // FMINV , , .
// IF_SVE_HQ_3A
diff --git a/src/coreclr/jit/emitarm64sve.cpp b/src/coreclr/jit/emitarm64sve.cpp
index 3eadf273290f8..19a1e89482a0e 100644
--- a/src/coreclr/jit/emitarm64sve.cpp
+++ b/src/coreclr/jit/emitarm64sve.cpp
@@ -3060,7 +3060,6 @@ void emitter::emitInsSve_R_R_R(instruction ins,
break;
case INS_sve_saddv:
- case INS_sve_uaddv:
assert(isFloatReg(reg1));
assert(isLowPredicateRegister(reg2));
assert(isVectorRegister(reg3));
@@ -3069,6 +3068,15 @@ void emitter::emitInsSve_R_R_R(instruction ins,
fmt = IF_SVE_AI_3A;
break;
+ case INS_sve_uaddv:
+ assert(isFloatReg(reg1));
+ assert(isLowPredicateRegister(reg2));
+ assert(isVectorRegister(reg3));
+ assert(insOptsScalableStandard(opt));
+ assert(insScalableOptsNone(sopt));
+ fmt = IF_SVE_AI_3A;
+ break;
+
case INS_sve_addqv:
unreached(); // TODO-SVE: Not yet supported.
assert(isVectorRegister(reg1));
@@ -4059,7 +4067,7 @@ void emitter::emitInsSve_R_R_R(instruction ins,
assert(isLowPredicateRegister(reg2));
assert(isVectorRegister(reg3));
assert(insOptsScalableFloat(opt));
- assert(isValidVectorElemsizeSveFloat(size));
+ assert(isScalableVectorSize(size));
assert(insScalableOptsNone(sopt));
fmt = IF_SVE_HE_3A;
break;
@@ -4069,7 +4077,7 @@ void emitter::emitInsSve_R_R_R(instruction ins,
assert(isLowPredicateRegister(reg2));
assert(isVectorRegister(reg3));
assert(insOptsScalableFloat(opt));
- assert(isValidVectorElemsizeSveFloat(size));
+ assert(isScalableVectorSize(size));
assert(insScalableOptsNone(sopt));
fmt = IF_SVE_HJ_3A;
break;
@@ -12618,7 +12626,7 @@ void emitter::emitInsSveSanityCheck(instrDesc* id)
assert(isVectorRegister(id->idReg1())); // ddddd
assert(isLowPredicateRegister(id->idReg2())); // ggg
assert(isVectorRegister(id->idReg3())); // mmmmm
- assert(isValidVectorElemsizeSveFloat(id->idOpSize()));
+ assert(isScalableVectorSize(id->idOpSize()));
break;
// Scalable to general register.
@@ -13211,11 +13219,20 @@ void emitter::emitInsSveSanityCheck(instrDesc* id)
// Scalable, widening to scalar SIMD.
case IF_SVE_AI_3A: // ........xx...... ...gggnnnnnddddd -- SVE integer add reduction (predicated)
- assert(insOptsScalableWide(id->idInsOpt())); // xx
+ switch (id->idIns())
+ {
+ case INS_sve_saddv:
+ assert(insOptsScalableWide(id->idInsOpt())); // xx
+ break;
+
+ default:
+ assert(insOptsScalableStandard(id->idInsOpt())); // xx
+ break;
+ }
assert(isVectorRegister(id->idReg1())); // ddddd
assert(isLowPredicateRegister(id->idReg2())); // ggg
assert(isVectorRegister(id->idReg3())); // mmmmm
- assert(isValidVectorElemsizeWidening(id->idOpSize()));
+ assert(isScalableVectorSize(id->idOpSize()));
break;
// Scalable, possibly FP.
diff --git a/src/coreclr/jit/hwintrinsic.h b/src/coreclr/jit/hwintrinsic.h
index 82cf179c742f4..dc1d2918b88d5 100644
--- a/src/coreclr/jit/hwintrinsic.h
+++ b/src/coreclr/jit/hwintrinsic.h
@@ -70,175 +70,176 @@ enum HWIntrinsicCategory : uint8_t
#else
#error Unsupported platform
#endif
+
enum HWIntrinsicFlag : unsigned int
{
HW_Flag_NoFlag = 0,
// Commutative
// - if a binary-op intrinsic is commutative (e.g., Add, Multiply), its op1 can be contained
- HW_Flag_Commutative = 0x1,
+ HW_Flag_Commutative = (1 << 0),
// NoCodeGen
// - should be transformed in the compiler front-end, cannot reach CodeGen
- HW_Flag_NoCodeGen = 0x2,
+ HW_Flag_NoCodeGen = (1 << 1),
// Multi-instruction
// - that one intrinsic can generate multiple instructions
- HW_Flag_MultiIns = 0x4,
+ HW_Flag_MultiIns = (1 << 2),
// Select base type using the first argument type
- HW_Flag_BaseTypeFromFirstArg = 0x8,
+ HW_Flag_BaseTypeFromFirstArg = (1 << 3),
// Select base type using the second argument type
- HW_Flag_BaseTypeFromSecondArg = 0x10,
+ HW_Flag_BaseTypeFromSecondArg = (1 << 4),
// Indicates compFloatingPointUsed does not need to be set.
- HW_Flag_NoFloatingPointUsed = 0x20,
+ HW_Flag_NoFloatingPointUsed = (1 << 5),
// NoJmpTable IMM
// the imm intrinsic does not need jumptable fallback when it gets non-const argument
- HW_Flag_NoJmpTableIMM = 0x40,
+ HW_Flag_NoJmpTableIMM = (1 << 6),
// Special codegen
// the intrinsics need special rules in CodeGen,
// but may be table-driven in the front-end
- HW_Flag_SpecialCodeGen = 0x80,
+ HW_Flag_SpecialCodeGen = (1 << 7),
// Special import
// the intrinsics need special rules in importer,
// but may be table-driven in the back-end
- HW_Flag_SpecialImport = 0x100,
+ HW_Flag_SpecialImport = (1 << 8),
// The intrinsic returns result in multiple registers.
- HW_Flag_MultiReg = 0x200,
+ HW_Flag_MultiReg = (1 << 9),
+
+ // The intrinsic has some barrier special side effect that should be tracked
+ HW_Flag_SpecialSideEffect_Barrier = (1 << 10),
+
+ // The intrinsic has some other special side effect that should be tracked
+ HW_Flag_SpecialSideEffect_Other = (1 << 11),
+
+ HW_Flag_SpecialSideEffectMask = (HW_Flag_SpecialSideEffect_Barrier | HW_Flag_SpecialSideEffect_Other),
-// The below is for defining platform-specific flags
+ // MaybeNoJmpTable IMM
+ // the imm intrinsic may not need jumptable fallback when it gets non-const argument
+ HW_Flag_MaybeNoJmpTableIMM = (1 << 12),
+
+ HW_Flag_CanBenefitFromConstantProp = (1 << 13),
+
+ // Used as a base for shifting the platform specific flags.
+ HW_Flag_PlatformBase = 13,
+#define HW_TARGET_FLAG(id) (unsigned int)(1 << (id + HW_Flag_PlatformBase))
+
+// Platform-specific flags
#if defined(TARGET_XARCH)
// Full range IMM intrinsic
// - the immediate value is valid on the full range of imm8 (0-255)
- HW_Flag_FullRangeIMM = 0x400,
+ HW_Flag_FullRangeIMM = HW_TARGET_FLAG(1),
// Maybe IMM
// the intrinsic has either imm or Vector overloads
- HW_Flag_MaybeIMM = 0x800,
+ HW_Flag_MaybeIMM = HW_TARGET_FLAG(2),
// Copy Upper bits
// some SIMD scalar intrinsics need the semantics of copying upper bits from the source operand
- HW_Flag_CopyUpperBits = 0x1000,
+ HW_Flag_CopyUpperBits = HW_TARGET_FLAG(3),
// Maybe Memory Load/Store
// - some intrinsics may have pointer overloads but without HW_Category_MemoryLoad/HW_Category_MemoryStore
- HW_Flag_MaybeMemoryLoad = 0x2000,
- HW_Flag_MaybeMemoryStore = 0x4000,
+ HW_Flag_MaybeMemoryLoad = HW_TARGET_FLAG(4),
+ HW_Flag_MaybeMemoryStore = HW_TARGET_FLAG(5),
// No Read/Modify/Write Semantics
// the intrinsic doesn't have read/modify/write semantics in two/three-operand form.
- HW_Flag_NoRMWSemantics = 0x8000,
+ HW_Flag_NoRMWSemantics = HW_TARGET_FLAG(6),
// NoContainment
// the intrinsic cannot be handled by containment,
// all the intrinsic that have explicit memory load/store semantics should have this flag
- HW_Flag_NoContainment = 0x10000,
+ HW_Flag_NoContainment = HW_TARGET_FLAG(7),
// Returns Per-Element Mask
// the intrinsic returns a vector containing elements that are either "all bits set" or "all bits clear"
// this output can be used as a per-element mask
- HW_Flag_ReturnsPerElementMask = 0x20000,
+ HW_Flag_ReturnsPerElementMask = HW_TARGET_FLAG(8),
// AvxOnlyCompatible
// the intrinsic can be used on hardware with AVX but not AVX2 support
- HW_Flag_AvxOnlyCompatible = 0x40000,
+ HW_Flag_AvxOnlyCompatible = HW_TARGET_FLAG(9),
// MaybeCommutative
// - if a binary-op intrinsic is maybe commutative (e.g., Max or Min for float/double), its op1 can possibly be
// contained
- HW_Flag_MaybeCommutative = 0x80000,
+ HW_Flag_MaybeCommutative = HW_TARGET_FLAG(10),
// The intrinsic has no EVEX compatible form
- HW_Flag_NoEvexSemantics = 0x100000,
+ HW_Flag_NoEvexSemantics = HW_TARGET_FLAG(11),
+
+ // The intrinsic is an RMW intrinsic
+ HW_Flag_RmwIntrinsic = HW_TARGET_FLAG(12),
+
+ // The intrinsic is a FusedMultiplyAdd intrinsic
+ HW_Flag_FmaIntrinsic = HW_TARGET_FLAG(13),
+
+ // The intrinsic is a PermuteVar2x intrinsic
+ HW_Flag_PermuteVar2x = HW_TARGET_FLAG(14),
+
+ // The intrinsic is an embedded broadcast compatible intrinsic
+ HW_Flag_EmbBroadcastCompatible = HW_TARGET_FLAG(15),
+
+ // The intrinsic is an embedded rounding compatible intrinsic
+ HW_Flag_EmbRoundingCompatible = HW_TARGET_FLAG(16),
+
+ // The intrinsic is an embedded masking incompatible intrinsic
+ HW_Flag_EmbMaskingIncompatible = HW_TARGET_FLAG(17),
#elif defined(TARGET_ARM64)
// The intrinsic has an immediate operand
// - the value can be (and should be) encoded in a corresponding instruction when the operand value is constant
- HW_Flag_HasImmediateOperand = 0x400,
+ HW_Flag_HasImmediateOperand = HW_TARGET_FLAG(1),
// The intrinsic has read/modify/write semantics in multiple-operands form.
- HW_Flag_HasRMWSemantics = 0x800,
+ HW_Flag_HasRMWSemantics = HW_TARGET_FLAG(2),
// The intrinsic operates on the lower part of a SIMD register
// - the upper part of the source registers are ignored
// - the upper part of the destination register is zeroed
- HW_Flag_SIMDScalar = 0x1000,
+ HW_Flag_SIMDScalar = HW_TARGET_FLAG(3),
// The intrinsic supports some sort of containment analysis
- HW_Flag_SupportsContainment = 0x2000,
+ HW_Flag_SupportsContainment = HW_TARGET_FLAG(4),
// The intrinsic needs consecutive registers
- HW_Flag_NeedsConsecutiveRegisters = 0x4000,
+ HW_Flag_NeedsConsecutiveRegisters = HW_TARGET_FLAG(5),
// The intrinsic uses scalable registers
- HW_Flag_Scalable = 0x8000,
+ HW_Flag_Scalable = HW_TARGET_FLAG(6),
// Returns Per-Element Mask
// the intrinsic returns a vector containing elements that are either "all bits set" or "all bits clear"
// this output can be used as a per-element mask
- HW_Flag_ReturnsPerElementMask = 0x10000,
+ HW_Flag_ReturnsPerElementMask = HW_TARGET_FLAG(7),
// The intrinsic uses a mask in arg1 to select elements present in the result
- HW_Flag_ExplicitMaskedOperation = 0x20000,
+ HW_Flag_ExplicitMaskedOperation = HW_TARGET_FLAG(8),
// The intrinsic uses a mask in arg1 to select elements present in the result, and must use a low register.
- HW_Flag_LowMaskedOperation = 0x40000,
+ HW_Flag_LowMaskedOperation = HW_TARGET_FLAG(9),
// The intrinsic can optionally use a mask in arg1 to select elements present in the result, which is not present in
// the API call
- HW_Flag_OptionalEmbeddedMaskedOperation = 0x80000,
+ HW_Flag_OptionalEmbeddedMaskedOperation = HW_TARGET_FLAG(10),
// The intrinsic uses a mask in arg1 to select elements present in the result, which is not present in the API call
- HW_Flag_EmbeddedMaskedOperation = 0x100000,
+ HW_Flag_EmbeddedMaskedOperation = HW_TARGET_FLAG(11),
+
+ // The intrinsic has an enum operand. Using this implies HW_Flag_HasImmediateOperand.
+ HW_Flag_HasEnumOperand = HW_TARGET_FLAG(12),
#else
#error Unsupported platform
#endif
-
- // The intrinsic has some barrier special side effect that should be tracked
- HW_Flag_SpecialSideEffect_Barrier = 0x200000,
-
- // The intrinsic has some other special side effect that should be tracked
- HW_Flag_SpecialSideEffect_Other = 0x400000,
-
- HW_Flag_SpecialSideEffectMask = (HW_Flag_SpecialSideEffect_Barrier | HW_Flag_SpecialSideEffect_Other),
-
- // MaybeNoJmpTable IMM
- // the imm intrinsic may not need jumptable fallback when it gets non-const argument
- HW_Flag_MaybeNoJmpTableIMM = 0x800000,
-
-#if defined(TARGET_XARCH)
- // The intrinsic is an RMW intrinsic
- HW_Flag_RmwIntrinsic = 0x1000000,
-
- // The intrinsic is a FusedMultiplyAdd intrinsic
- HW_Flag_FmaIntrinsic = 0x2000000,
-
- // The intrinsic is a PermuteVar2x intrinsic
- HW_Flag_PermuteVar2x = 0x4000000,
-
- // The intrinsic is an embedded broadcast compatible intrinsic
- HW_Flag_EmbBroadcastCompatible = 0x8000000,
-
- // The intrinsic is an embedded rounding compatible intrinsic
- HW_Flag_EmbRoundingCompatible = 0x10000000,
-
- // The intrinsic is an embedded masking incompatible intrinsic
- HW_Flag_EmbMaskingIncompatible = 0x20000000,
-#elif defined(TARGET_ARM64)
-
- // The intrinsic has an enum operand. Using this implies HW_Flag_HasImmediateOperand.
- HW_Flag_HasEnumOperand = 0x1000000,
-
-#endif // TARGET_XARCH
-
- HW_Flag_CanBenefitFromConstantProp = 0x80000000,
};
#if defined(TARGET_XARCH)
diff --git a/src/coreclr/jit/hwintrinsiclistarm64sve.h b/src/coreclr/jit/hwintrinsiclistarm64sve.h
index ef9740e455652..538f42363bbe1 100644
--- a/src/coreclr/jit/hwintrinsiclistarm64sve.h
+++ b/src/coreclr/jit/hwintrinsiclistarm64sve.h
@@ -19,6 +19,7 @@
// Sve
HARDWARE_INTRINSIC(Sve, Abs, -1, -1, false, {INS_sve_abs, INS_invalid, INS_sve_abs, INS_invalid, INS_sve_abs, INS_invalid, INS_sve_abs, INS_invalid, INS_sve_fabs, INS_sve_fabs}, HW_Category_SIMD, HW_Flag_Scalable|HW_Flag_EmbeddedMaskedOperation)
HARDWARE_INTRINSIC(Sve, Add, -1, -1, false, {INS_sve_add, INS_sve_add, INS_sve_add, INS_sve_add, INS_sve_add, INS_sve_add, INS_sve_add, INS_sve_add, INS_sve_fadd, INS_sve_fadd}, HW_Category_SIMD, HW_Flag_Scalable|HW_Flag_OptionalEmbeddedMaskedOperation|HW_Flag_HasRMWSemantics|HW_Flag_LowMaskedOperation)
+HARDWARE_INTRINSIC(Sve, AddAcross, -1, 1, true, {INS_sve_saddv, INS_sve_uaddv, INS_sve_saddv, INS_sve_uaddv, INS_sve_saddv, INS_sve_uaddv, INS_sve_uaddv, INS_sve_uaddv, INS_sve_faddv, INS_sve_faddv}, HW_Category_SIMD, HW_Flag_Scalable|HW_Flag_BaseTypeFromFirstArg|HW_Flag_EmbeddedMaskedOperation)
HARDWARE_INTRINSIC(Sve, ConditionalSelect, -1, 3, true, {INS_sve_sel, INS_sve_sel, INS_sve_sel, INS_sve_sel, INS_sve_sel, INS_sve_sel, INS_sve_sel, INS_sve_sel, INS_sve_sel, INS_sve_sel}, HW_Category_SIMD, HW_Flag_Scalable|HW_Flag_ExplicitMaskedOperation|HW_Flag_SupportsContainment)
HARDWARE_INTRINSIC(Sve, Count16BitElements, 0, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_cnth, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_Scalable|HW_Flag_HasEnumOperand|HW_Flag_SpecialCodeGen|HW_Flag_NoFloatingPointUsed)
HARDWARE_INTRINSIC(Sve, Count32BitElements, 0, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_cntw, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_Scalable|HW_Flag_HasEnumOperand|HW_Flag_SpecialCodeGen|HW_Flag_NoFloatingPointUsed)
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 3b992e440ef6b..1b7bf1618a22f 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
@@ -148,6 +148,68 @@ internal Arm64() { }
///
public static unsafe Vector Add(Vector left, Vector right) { throw new PlatformNotSupportedException(); }
+ /// AddAcross : Add reduction
+
+ ///
+ /// float64_t svaddv[_f64](svbool_t pg, svfloat64_t op)
+ /// FADDV Dresult, Pg, Zop.D
+ ///
+ public static unsafe Vector AddAcross(Vector value) { throw new PlatformNotSupportedException(); }
+
+ ///
+ /// int64_t svaddv[_s16](svbool_t pg, svint16_t op)
+ /// SADDV Dresult, Pg, Zop.H
+ ///
+ public static unsafe Vector AddAcross(Vector value) { throw new PlatformNotSupportedException(); }
+
+ ///
+ /// int64_t svaddv[_s32](svbool_t pg, svint32_t op)
+ /// SADDV Dresult, Pg, Zop.S
+ ///
+ public static unsafe Vector AddAcross(Vector value) { throw new PlatformNotSupportedException(); }
+
+ ///
+ /// int64_t svaddv[_s8](svbool_t pg, svint8_t op)
+ /// SADDV Dresult, Pg, Zop.B
+ ///
+ public static unsafe Vector AddAcross(Vector value) { throw new PlatformNotSupportedException(); }
+
+ ///
+ /// int64_t svaddv[_s64](svbool_t pg, svint64_t op)
+ /// UADDV Dresult, Pg, Zop.D
+ ///
+ public static unsafe Vector AddAcross(Vector value) { throw new PlatformNotSupportedException(); }
+
+ ///
+ /// float32_t svaddv[_f32](svbool_t pg, svfloat32_t op)
+ /// FADDV Sresult, Pg, Zop.S
+ ///
+ public static unsafe Vector AddAcross(Vector value) { throw new PlatformNotSupportedException(); }
+
+ ///
+ /// uint64_t svaddv[_u8](svbool_t pg, svuint8_t op)
+ /// UADDV Dresult, Pg, Zop.B
+ ///
+ public static unsafe Vector AddAcross(Vector value) { throw new PlatformNotSupportedException(); }
+
+ ///
+ /// uint64_t svaddv[_u16](svbool_t pg, svuint16_t op)
+ /// UADDV Dresult, Pg, Zop.H
+ ///
+ public static unsafe Vector AddAcross(Vector value) { throw new PlatformNotSupportedException(); }
+
+ ///
+ /// uint64_t svaddv[_u32](svbool_t pg, svuint32_t op)
+ /// UADDV Dresult, Pg, Zop.S
+ ///
+ public static unsafe Vector AddAcross(Vector value) { throw new PlatformNotSupportedException(); }
+
+ ///
+ /// uint64_t svaddv[_u64](svbool_t pg, svuint64_t op)
+ /// UADDV Dresult, Pg, Zop.D
+ ///
+ public static unsafe Vector AddAcross(Vector value) { throw new PlatformNotSupportedException(); }
+
/// ConditionalSelect : Conditionally select elements
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 0f4f57dad8e9b..1221ee4ec2d68 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
@@ -177,6 +177,69 @@ internal Arm64() { }
public static unsafe Vector Add(Vector left, Vector right) => Add(left, right);
+ /// AddAcross : Add reduction
+
+ ///
+ /// float64_t svaddv[_f64](svbool_t pg, svfloat64_t op)
+ /// FADDV Dresult, Pg, Zop.D
+ ///
+ public static unsafe Vector AddAcross(Vector value) => AddAcross(value);
+
+ ///
+ /// int64_t svaddv[_s16](svbool_t pg, svint16_t op)
+ /// SADDV Dresult, Pg, Zop.H
+ ///
+ public static unsafe Vector AddAcross(Vector value) => AddAcross(value);
+
+ ///
+ /// int64_t svaddv[_s32](svbool_t pg, svint32_t op)
+ /// SADDV Dresult, Pg, Zop.S
+ ///
+ public static unsafe Vector AddAcross(Vector value) => AddAcross(value);
+
+ ///
+ /// int64_t svaddv[_s8](svbool_t pg, svint8_t op)
+ /// SADDV Dresult, Pg, Zop.B
+ ///
+ public static unsafe Vector AddAcross(Vector value) => AddAcross(value);
+
+ ///
+ /// int64_t svaddv[_s64](svbool_t pg, svint64_t op)
+ /// UADDV Dresult, Pg, Zop.D
+ ///
+ public static unsafe Vector AddAcross(Vector value) => AddAcross(value);
+
+ ///
+ /// float32_t svaddv[_f32](svbool_t pg, svfloat32_t op)
+ /// FADDV Sresult, Pg, Zop.S
+ ///
+ public static unsafe Vector AddAcross(Vector value) => AddAcross(value);
+
+ ///
+ /// uint64_t svaddv[_u8](svbool_t pg, svuint8_t op)
+ /// UADDV Dresult, Pg, Zop.B
+ ///
+ public static unsafe Vector AddAcross(Vector value) => AddAcross(value);
+
+ ///
+ /// uint64_t svaddv[_u16](svbool_t pg, svuint16_t op)
+ /// UADDV Dresult, Pg, Zop.H
+ ///
+ public static unsafe Vector AddAcross(Vector value) => AddAcross(value);
+
+ ///
+ /// uint64_t svaddv[_u32](svbool_t pg, svuint32_t op)
+ /// UADDV Dresult, Pg, Zop.S
+ ///
+ public static unsafe Vector AddAcross(Vector value) => AddAcross(value);
+
+ ///
+ /// uint64_t svaddv[_u64](svbool_t pg, svuint64_t op)
+ /// UADDV Dresult, Pg, Zop.D
+ ///
+ public static unsafe Vector AddAcross(Vector value) => AddAcross(value);
+
+
/// ConditionalSelect : Conditionally select elements
///
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 881100ff95976..72470a15147e7 100644
--- a/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs
+++ b/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs
@@ -4187,6 +4187,16 @@ internal Arm64() { }
public static System.Numerics.Vector Add(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; }
public static System.Numerics.Vector Add(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; }
public static System.Numerics.Vector Add(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; }
+ public static System.Numerics.Vector AddAcross(System.Numerics.Vector value) { throw null; }
+ public static System.Numerics.Vector AddAcross(System.Numerics.Vector value) { throw null; }
+ public static System.Numerics.Vector AddAcross(System.Numerics.Vector value) { throw null; }
+ public static System.Numerics.Vector AddAcross(System.Numerics.Vector value) { throw null; }
+ public static System.Numerics.Vector AddAcross(System.Numerics.Vector value) { throw null; }
+ public static System.Numerics.Vector AddAcross(System.Numerics.Vector value) { throw null; }
+ public static System.Numerics.Vector AddAcross(System.Numerics.Vector value) { throw null; }
+ public static System.Numerics.Vector AddAcross(System.Numerics.Vector value) { throw null; }
+ public static System.Numerics.Vector AddAcross(System.Numerics.Vector value) { throw null; }
+ public static System.Numerics.Vector AddAcross(System.Numerics.Vector value) { throw null; }
public static ulong Count16BitElements([ConstantExpected] SveMaskPattern pattern = SveMaskPattern.All) { throw null; }
public static ulong Count32BitElements([ConstantExpected] SveMaskPattern pattern = SveMaskPattern.All) { throw null; }
public static ulong Count64BitElements([ConstantExpected] SveMaskPattern pattern = SveMaskPattern.All) { throw null; }
diff --git a/src/tests/Common/GenerateHWIntrinsicTests/GenerateHWIntrinsicTests_Arm.cs b/src/tests/Common/GenerateHWIntrinsicTests/GenerateHWIntrinsicTests_Arm.cs
index db964d4793e1b..df91f8878d27a 100644
--- a/src/tests/Common/GenerateHWIntrinsicTests/GenerateHWIntrinsicTests_Arm.cs
+++ b/src/tests/Common/GenerateHWIntrinsicTests/GenerateHWIntrinsicTests_Arm.cs
@@ -98,29 +98,30 @@
(string templateFileName, string outputTemplateName, Dictionary templateData)[] Templates = new[]
{
- ("_UnaryOpScalarTestTemplate.template", "DuplicateTest.template", new Dictionary { ["TemplateName"] = "Duplicate", ["TemplateValidationLogic"] = SimpleOpTest_ValidationLogic }),
- ("_ImmUnaryOpTestTemplate.template", "ImmUnOpTest.template", new Dictionary { ["TemplateName"] = "Imm", ["TemplateValidationLogic"] = SimpleOpTest_ValidationLogic }),
- ("_ImmUnaryOpTestTemplate.template", "VecImmUnOpTest.template", new Dictionary { ["TemplateName"] = "Imm", ["TemplateValidationLogic"] = SimpleVecOpTest_ValidationLogic }),
- ("_ImmTernaryOpTestTemplate.template", "ImmTernOpTest.template", new Dictionary { ["TemplateName"] = "Imm", ["TemplateValidationLogic"] = SimpleVecOpTest_ValidationLogic }),
- ("_ImmOpTestTemplate.template", "ImmOpTest.template", new Dictionary { ["TemplateName"] = "Imm", ["TemplateValidationLogic"] = SimpleOpTest_ValidationLogic }),
- ("_ImmBinaryOpTestTemplate.template", "ImmBinOpTest.template", new Dictionary { ["TemplateName"] = "Imm", ["TemplateValidationLogic"] = SimpleOpTest_ValidationLogic }),
- ("_ImmBinaryOpTestTemplate.template", "VecImmBinOpTest.template", new Dictionary { ["TemplateName"] = "Imm", ["TemplateValidationLogic"] = SimpleVecOpTest_ValidationLogic }),
- ("_BinaryOpTestTemplate.template", "SimpleBinOpTest.template", new Dictionary { ["TemplateName"] = "Simple", ["TemplateValidationLogic"] = SimpleOpTest_ValidationLogic }),
- ("_TernaryOpTestTemplate.template", "VecTernOpTest.template", new Dictionary { ["TemplateName"] = "Simple", ["TemplateValidationLogic"] = SimpleVecOpTest_ValidationLogic }),
- ("_ImmTernaryOpTestTemplate.template", "VecImmTernOpTest.template", new Dictionary { ["TemplateName"] = "Simple", ["TemplateValidationLogic"] = SimpleVecOpTest_ValidationLogic }),
- ("_ImmTernaryOpTestTemplate.template", "SimpleImmTernOpTest.template", new Dictionary { ["TemplateName"] = "Simple", ["TemplateValidationLogic"] = SimpleOpTest_ValidationLogic }),
- ("_UnaryOpTestTemplate.template", "SimpleUnOpTest.template", new Dictionary { ["TemplateName"] = "Simple", ["TemplateValidationLogic"] = SimpleOpTest_ValidationLogic }),
- ("_UnaryOpTestTemplate.template", "SimpleVecOpTest.template", new Dictionary { ["TemplateName"] = "Simple", ["TemplateValidationLogic"] = SimpleVecOpTest_ValidationLogic }),
- ("_BinaryOpTestTemplate.template", "VecPairBinOpTest.template", new Dictionary { ["TemplateName"] = "Simple", ["TemplateValidationLogic"] = VecPairBinOpTest_ValidationLogic }),
- ("_BinaryOp_SveTestTemplate.template", "SveVecPairBinOpTest.template", new Dictionary { ["TemplateName"] = "Simple", ["TemplateValidationLogic"] = VecPairBinOpTest_ValidationLogic }),
- ("_UnaryOpTestTemplate.template", "VecReduceUnOpTest.template", new Dictionary { ["TemplateName"] = "Simple", ["TemplateValidationLogic"] = VecReduceOpTest_ValidationLogic }),
- ("_BinaryOpTestTemplate.template", "VecBinOpTest.template", new Dictionary { ["TemplateName"] = "Simple", ["TemplateValidationLogic"] = SimpleVecOpTest_ValidationLogic }),
- ("_TernaryOpTestTemplate.template", "SimpleTernOpTest.template", new Dictionary { ["TemplateName"] = "Simple", ["TemplateValidationLogic"] = SimpleOpTest_ValidationLogic }),
- ("_UnaryOpTestTemplate.template", "SecureHashUnOpTest.template", new Dictionary { ["TemplateName"] = "SecureHash", ["TemplateValidationLogic"] = SecureHashOpTest_ValidationLogic }),
- ("_BinaryOpTestTemplate.template", "SecureHashBinOpTest.template", new Dictionary { ["TemplateName"] = "SecureHash", ["TemplateValidationLogic"] = SecureHashOpTest_ValidationLogic }),
- ("_TernaryOpTestTemplate.template", "SecureHashTernOpTest.template", new Dictionary { ["TemplateName"] = "SecureHash", ["TemplateValidationLogic"] = SecureHashOpTest_ValidationLogic }),
- ("_SveUnaryOpTestTemplate.template", "SveSimpleVecOpTest.template", new Dictionary { ["TemplateName"] = "Simple", ["TemplateValidationLogic"] = SimpleVecOpTest_ValidationLogic, ["TemplateValidationLogicForCndSel"] = SimpleVecOpTest_ValidationLogicForCndSel }),
- ("_SveBinaryOpTestTemplate.template", "SveVecBinOpTest.template", new Dictionary { ["TemplateName"] = "Simple", ["TemplateValidationLogic"] = SimpleVecOpTest_ValidationLogic, ["TemplateValidationLogicForCndSel"] = SimpleVecOpTest_ValidationLogicForCndSel }),
+ ("_UnaryOpScalarTestTemplate.template", "DuplicateTest.template", new Dictionary { ["TemplateName"] = "Duplicate", ["TemplateValidationLogic"] = SimpleOpTest_ValidationLogic }),
+ ("_ImmUnaryOpTestTemplate.template", "ImmUnOpTest.template", new Dictionary { ["TemplateName"] = "Imm", ["TemplateValidationLogic"] = SimpleOpTest_ValidationLogic }),
+ ("_ImmUnaryOpTestTemplate.template", "VecImmUnOpTest.template", new Dictionary { ["TemplateName"] = "Imm", ["TemplateValidationLogic"] = SimpleVecOpTest_ValidationLogic }),
+ ("_ImmTernaryOpTestTemplate.template", "ImmTernOpTest.template", new Dictionary { ["TemplateName"] = "Imm", ["TemplateValidationLogic"] = SimpleVecOpTest_ValidationLogic }),
+ ("_ImmOpTestTemplate.template", "ImmOpTest.template", new Dictionary { ["TemplateName"] = "Imm", ["TemplateValidationLogic"] = SimpleOpTest_ValidationLogic }),
+ ("_ImmBinaryOpTestTemplate.template", "ImmBinOpTest.template", new Dictionary { ["TemplateName"] = "Imm", ["TemplateValidationLogic"] = SimpleOpTest_ValidationLogic }),
+ ("_ImmBinaryOpTestTemplate.template", "VecImmBinOpTest.template", new Dictionary { ["TemplateName"] = "Imm", ["TemplateValidationLogic"] = SimpleVecOpTest_ValidationLogic }),
+ ("_BinaryOpTestTemplate.template", "SimpleBinOpTest.template", new Dictionary { ["TemplateName"] = "Simple", ["TemplateValidationLogic"] = SimpleOpTest_ValidationLogic }),
+ ("_TernaryOpTestTemplate.template", "VecTernOpTest.template", new Dictionary { ["TemplateName"] = "Simple", ["TemplateValidationLogic"] = SimpleVecOpTest_ValidationLogic }),
+ ("_ImmTernaryOpTestTemplate.template", "VecImmTernOpTest.template", new Dictionary { ["TemplateName"] = "Simple", ["TemplateValidationLogic"] = SimpleVecOpTest_ValidationLogic }),
+ ("_ImmTernaryOpTestTemplate.template", "SimpleImmTernOpTest.template", new Dictionary { ["TemplateName"] = "Simple", ["TemplateValidationLogic"] = SimpleOpTest_ValidationLogic }),
+ ("_UnaryOpTestTemplate.template", "SimpleUnOpTest.template", new Dictionary { ["TemplateName"] = "Simple", ["TemplateValidationLogic"] = SimpleOpTest_ValidationLogic }),
+ ("_UnaryOpTestTemplate.template", "SimpleVecOpTest.template", new Dictionary { ["TemplateName"] = "Simple", ["TemplateValidationLogic"] = SimpleVecOpTest_ValidationLogic }),
+ ("_BinaryOpTestTemplate.template", "VecPairBinOpTest.template", new Dictionary { ["TemplateName"] = "Simple", ["TemplateValidationLogic"] = VecPairBinOpTest_ValidationLogic }),
+ ("_BinaryOp_SveTestTemplate.template", "SveVecPairBinOpTest.template", new Dictionary { ["TemplateName"] = "Simple", ["TemplateValidationLogic"] = VecPairBinOpTest_ValidationLogic }),
+ ("_UnaryOpTestTemplate.template", "VecReduceUnOpTest.template", new Dictionary { ["TemplateName"] = "Simple", ["TemplateValidationLogic"] = VecReduceOpTest_ValidationLogic }),
+ ("_BinaryOpTestTemplate.template", "VecBinOpTest.template", new Dictionary { ["TemplateName"] = "Simple", ["TemplateValidationLogic"] = SimpleVecOpTest_ValidationLogic }),
+ ("_TernaryOpTestTemplate.template", "SimpleTernOpTest.template", new Dictionary { ["TemplateName"] = "Simple", ["TemplateValidationLogic"] = SimpleOpTest_ValidationLogic }),
+ ("_UnaryOpTestTemplate.template", "SecureHashUnOpTest.template", new Dictionary { ["TemplateName"] = "SecureHash", ["TemplateValidationLogic"] = SecureHashOpTest_ValidationLogic }),
+ ("_BinaryOpTestTemplate.template", "SecureHashBinOpTest.template", new Dictionary { ["TemplateName"] = "SecureHash", ["TemplateValidationLogic"] = SecureHashOpTest_ValidationLogic }),
+ ("_TernaryOpTestTemplate.template", "SecureHashTernOpTest.template", new Dictionary { ["TemplateName"] = "SecureHash", ["TemplateValidationLogic"] = SecureHashOpTest_ValidationLogic }),
+ ("_SveUnaryOpTestTemplate.template", "SveSimpleVecOpTest.template", new Dictionary { ["TemplateName"] = "Simple", ["TemplateValidationLogic"] = SimpleVecOpTest_ValidationLogic, ["TemplateValidationLogicForCndSel"] = SimpleVecOpTest_ValidationLogicForCndSel }),
+ ("_SveBinaryOpTestTemplate.template", "SveVecBinOpTest.template", new Dictionary { ["TemplateName"] = "Simple", ["TemplateValidationLogic"] = SimpleVecOpTest_ValidationLogic, ["TemplateValidationLogicForCndSel"] = SimpleVecOpTest_ValidationLogicForCndSel }),
+ ("_SveMinimalUnaryOpTestTemplate.template", "SveVecReduceUnOpTest.template", new Dictionary { ["TemplateName"] = "Simple", ["TemplateValidationLogic"] = VecReduceOpTest_ValidationLogic }),
};
(string templateFileName, Dictionary templateData)[] AdvSimdInputs = new []
@@ -2909,6 +2910,17 @@
("SveVecBinOpTest.template", new Dictionary { ["TestName"] = "Sve_Add_uint", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "Add", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.Add(left[i], right[i]) != result[i]", ["GetIterResult"] = "Helpers.Add(left[i], right[i])"}),
("SveVecBinOpTest.template", new Dictionary { ["TestName"] = "Sve_Add_ulong", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "Add", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["ValidateIterResult"] = "Helpers.Add(left[i], right[i]) != result[i]", ["GetIterResult"] = "Helpers.Add(left[i], right[i])"}),
+ ("SveVecReduceUnOpTest.template", new Dictionary { ["TestName"] = "Sve_AddAcross_float", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "AddAcross", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["ValidateReduceOpResult"] = "Helpers.AddAcrossRecursivePairwise(firstOp) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0.0"}),
+ ("SveVecReduceUnOpTest.template", new Dictionary { ["TestName"] = "Sve_AddAcross_double", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "AddAcross", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Double", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["ValidateReduceOpResult"] = "Helpers.AddAcrossRecursivePairwise(firstOp) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0.0"}),
+ ("SveVecReduceUnOpTest.template", new Dictionary { ["TestName"] = "Sve_AddAcross_long_sbyte", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "AddAcross", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["ValidateReduceOpResult"] = "Helpers.AddAcrossWideningLong(firstOp) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}),
+ ("SveVecReduceUnOpTest.template", new Dictionary { ["TestName"] = "Sve_AddAcross_long_short", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "AddAcross", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["ValidateReduceOpResult"] = "Helpers.AddAcrossWideningLong(firstOp) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}),
+ ("SveVecReduceUnOpTest.template", new Dictionary { ["TestName"] = "Sve_AddAcross_long_int", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "AddAcross", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["ValidateReduceOpResult"] = "Helpers.AddAcrossWidening(firstOp) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}),
+ ("SveVecReduceUnOpTest.template", new Dictionary { ["TestName"] = "Sve_AddAcross_long", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "AddAcross", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["ValidateReduceOpResult"] = "Helpers.AddAcross(firstOp) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}),
+ ("SveVecReduceUnOpTest.template", new Dictionary { ["TestName"] = "Sve_AddAcross_ulong_byte", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "AddAcross", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["ValidateReduceOpResult"] = "Helpers.AddAcrossWideningULong(firstOp) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}),
+ ("SveVecReduceUnOpTest.template", new Dictionary { ["TestName"] = "Sve_AddAcross_ulong_ushort", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "AddAcross", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["ValidateReduceOpResult"] = "Helpers.AddAcrossWideningULong(firstOp) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}),
+ ("SveVecReduceUnOpTest.template", new Dictionary { ["TestName"] = "Sve_AddAcross_ulong_uint", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "AddAcross", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["ValidateReduceOpResult"] = "Helpers.AddAcrossWidening(firstOp) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}),
+ ("SveVecReduceUnOpTest.template", new Dictionary { ["TestName"] = "Sve_AddAcross_ulong", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "AddAcross", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["ValidateReduceOpResult"] = "Helpers.AddAcross(firstOp) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}),
+
("SveConditionalSelect.template", new Dictionary { ["TestName"] = "Sve_ConditionalSelect_float", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "ConditionalSelect", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "Single", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "Single", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp3"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "(firstOp[i] != 0 ? (result[i] != secondOp[i]) : (result[i] != thirdOp[i]))",}),
("SveConditionalSelect.template", new Dictionary { ["TestName"] = "Sve_ConditionalSelect_double", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "ConditionalSelect", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "Double", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "Double", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp3"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "(firstOp[i] != 0 ? (result[i] != secondOp[i]) : (result[i] != thirdOp[i]))",}),
("SveConditionalSelect.template", new Dictionary { ["TestName"] = "Sve_ConditionalSelect_sbyte", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "ConditionalSelect", ["RetVectorType"] = "Vector", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "SByte", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "SByte", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp3"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "(firstOp[i] != 0 ? (result[i] != secondOp[i]) : (result[i] != thirdOp[i]))",}),
diff --git a/src/tests/JIT/HardwareIntrinsics/Arm/Shared/Helpers.cs b/src/tests/JIT/HardwareIntrinsics/Arm/Shared/Helpers.cs
index 4b44b29337573..232bfdcbb2121 100644
--- a/src/tests/JIT/HardwareIntrinsics/Arm/Shared/Helpers.cs
+++ b/src/tests/JIT/HardwareIntrinsics/Arm/Shared/Helpers.cs
@@ -1443,6 +1443,8 @@ public static float CompareTest(float left, float right)
public static short AddAcrossWidening(sbyte[] op1) => Reduce(AddWidening, op1);
+ public static long AddAcrossWideningLong(sbyte[] op1) => Reduce(AddWidening, op1);
+
public static short AddPairwiseWidening(sbyte[] op1, int i) => AddWidening(op1[2 * i], op1[2 * i + 1]);
public static short AddPairwiseWideningAndAdd(short[] op1, sbyte[] op2, int i) => (short)(op1[i] + AddWidening(op2[2 * i], op2[2 * i + 1]));
@@ -1469,6 +1471,8 @@ private static sbyte HighNarrowing(short op1, bool round)
public static short AddWidening(short op1, sbyte op2) => (short)(op1 + op2);
+ public static long AddWidening(long op1, sbyte op2) => (long)(op1 + (long)op2);
+
public static short AddWideningUpper(sbyte[] op1, sbyte[] op2, int i) => AddWidening(op1[i + op1.Length / 2], op2[i + op2.Length / 2]);
public static short AddWideningUpper(short[] op1, sbyte[] op2, int i) => AddWidening(op1[i], op2[i + op2.Length / 2]);
@@ -1533,6 +1537,18 @@ private static short Reduce(Func reduceOp, sbyte[] op1)
return acc;
}
+ private static long Reduce(Func reduceOp, sbyte[] op1)
+ {
+ long acc = op1[0];
+
+ for (int i = 1; i < op1.Length; i++)
+ {
+ acc = reduceOp(acc, op1[i]);
+ }
+
+ return acc;
+ }
+
public static uint AbsoluteDifferenceWidening(short op1, short op2) => op1 < op2 ? (uint)(op2 - op1) : (uint)(op1 - op2);
public static uint AbsoluteDifferenceWideningUpper(short[] op1, short[] op2, int i) => AbsoluteDifferenceWidening(op1[i + op1.Length / 2], op2[i + op2.Length / 2]);
@@ -1543,6 +1559,8 @@ private static short Reduce(Func reduceOp, sbyte[] op1)
public static int AddAcrossWidening(short[] op1) => Reduce(AddWidening, op1);
+ public static long AddAcrossWideningLong(short[] op1) => Reduce(AddWidening, op1);
+
public static int AddPairwiseWidening(short[] op1, int i) => AddWidening(op1[2 * i], op1[2 * i + 1]);
public static int AddPairwiseWideningAndAdd(int[] op1, short[] op2, int i) => (int)(op1[i] + AddWidening(op2[2 * i], op2[2 * i + 1]));
@@ -1569,6 +1587,8 @@ private static short HighNarrowing(int op1, bool round)
public static int AddWidening(int op1, short op2) => (int)(op1 + op2);
+ public static long AddWidening(long op1, short op2) => (long)(op1 + (long)op2);
+
public static int AddWideningUpper(short[] op1, short[] op2, int i) => AddWidening(op1[i + op1.Length / 2], op2[i + op2.Length / 2]);
public static int AddWideningUpper(int[] op1, short[] op2, int i) => AddWidening(op1[i], op2[i + op2.Length / 2]);
@@ -1633,6 +1653,18 @@ private static int Reduce(Func reduceOp, short[] op1)
return acc;
}
+ private static long Reduce(Func reduceOp, short[] op1)
+ {
+ long acc = op1[0];
+
+ for (int i = 1; i < op1.Length; i++)
+ {
+ acc = reduceOp(acc, op1[i]);
+ }
+
+ return acc;
+ }
+
public static ulong AbsoluteDifferenceWidening(int op1, int op2) => op1 < op2 ? (ulong)(op2 - op1) : (ulong)(op1 - op2);
public static ulong AbsoluteDifferenceWideningUpper(int[] op1, int[] op2, int i) => AbsoluteDifferenceWidening(op1[i + op1.Length / 2], op2[i + op2.Length / 2]);
@@ -1743,6 +1775,8 @@ private static long Reduce(Func reduceOp, int[] op1)
public static ushort AddAcrossWidening(byte[] op1) => Reduce(AddWidening, op1);
+ public static ulong AddAcrossWideningULong(byte[] op1) => Reduce(AddWidening, op1);
+
public static ushort AddPairwiseWidening(byte[] op1, int i) => AddWidening(op1[2 * i], op1[2 * i + 1]);
public static ushort AddPairwiseWideningAndAdd(ushort[] op1, byte[] op2, int i) => (ushort)(op1[i] + AddWidening(op2[2 * i], op2[2 * i + 1]));
@@ -1769,6 +1803,8 @@ private static byte HighNarrowing(ushort op1, bool round)
public static ushort AddWidening(ushort op1, byte op2) => (ushort)(op1 + op2);
+ public static ulong AddWidening(ulong op1, byte op2) => (ulong)(op1 + (ulong)op2);
+
public static ushort AddWideningUpper(byte[] op1, byte[] op2, int i) => AddWidening(op1[i + op1.Length / 2], op2[i + op2.Length / 2]);
public static ushort AddWideningUpper(ushort[] op1, byte[] op2, int i) => AddWidening(op1[i], op2[i + op2.Length / 2]);
@@ -1833,6 +1869,18 @@ private static ushort Reduce(Func reduceOp, byte[] op1)
return acc;
}
+ private static ulong Reduce(Func reduceOp, byte[] op1)
+ {
+ ulong acc = op1[0];
+
+ for (int i = 1; i < op1.Length; i++)
+ {
+ acc = reduceOp(acc, op1[i]);
+ }
+
+ return acc;
+ }
+
public static uint AbsoluteDifferenceWidening(ushort op1, ushort op2) => op1 < op2 ? (uint)(op2 - op1) : (uint)(op1 - op2);
public static uint AbsoluteDifferenceWideningUpper(ushort[] op1, ushort[] op2, int i) => AbsoluteDifferenceWidening(op1[i + op1.Length / 2], op2[i + op2.Length / 2]);
@@ -1843,6 +1891,8 @@ private static ushort Reduce(Func reduceOp, byte[] op1)
public static uint AddAcrossWidening(ushort[] op1) => Reduce(AddWidening, op1);
+ public static ulong AddAcrossWideningULong(ushort[] op1) => Reduce(AddWidening, op1);
+
public static uint AddPairwiseWidening(ushort[] op1, int i) => AddWidening(op1[2 * i], op1[2 * i + 1]);
public static uint AddPairwiseWideningAndAdd(uint[] op1, ushort[] op2, int i) => (uint)(op1[i] + AddWidening(op2[2 * i], op2[2 * i + 1]));
@@ -1869,6 +1919,8 @@ private static ushort HighNarrowing(uint op1, bool round)
public static uint AddWidening(uint op1, ushort op2) => (uint)(op1 + op2);
+ public static ulong AddWidening(ulong op1, ushort op2) => (ulong)(op1 + (ulong)op2);
+
public static uint AddWideningUpper(ushort[] op1, ushort[] op2, int i) => AddWidening(op1[i + op1.Length / 2], op2[i + op2.Length / 2]);
public static uint AddWideningUpper(uint[] op1, ushort[] op2, int i) => AddWidening(op1[i], op2[i + op2.Length / 2]);
@@ -1933,6 +1985,18 @@ private static uint Reduce(Func reduceOp, ushort[] op1)
return acc;
}
+ private static ulong Reduce(Func reduceOp, ushort[] op1)
+ {
+ ulong acc = op1[0];
+
+ for (int i = 1; i < op1.Length; i++)
+ {
+ acc = reduceOp(acc, op1[i]);
+ }
+
+ return acc;
+ }
+
public static ulong AbsoluteDifferenceWidening(uint op1, uint op2) => op1 < op2 ? (ulong)(op2 - op1) : (ulong)(op1 - op2);
public static ulong AbsoluteDifferenceWideningUpper(uint[] op1, uint[] op2, int i) => AbsoluteDifferenceWidening(op1[i + op1.Length / 2], op2[i + op2.Length / 2]);
@@ -2033,6 +2097,9 @@ private static ulong Reduce(Func reduceOp, uint[] op1)
return acc;
}
+ public static double AddWidening(double op1, float op2) => (double)(op1 + (double)op2);
+
+
private static bool SignedSatQ(short val, out sbyte result)
{
bool saturated = false;
@@ -5134,6 +5201,42 @@ private static uint Reduce(Func reduceOp, uint[] op1)
return acc;
}
+ public static long AddAcross(long[] op1) => Reduce(Add, op1);
+
+ public static long MaxAcross(long[] op1) => Reduce(Max, op1);
+
+ public static long MinAcross(long[] op1) => Reduce(Min, op1);
+
+ private static long Reduce(Func reduceOp, long[] op1)
+ {
+ long acc = op1[0];
+
+ for (int i = 1; i < op1.Length; i++)
+ {
+ acc = reduceOp(acc, op1[i]);
+ }
+
+ return acc;
+ }
+
+ public static ulong AddAcross(ulong[] op1) => Reduce(Add, op1);
+
+ public static ulong MaxAcross(ulong[] op1) => Reduce(Max, op1);
+
+ public static ulong MinAcross(ulong[] op1) => Reduce(Min, op1);
+
+ private static ulong Reduce(Func reduceOp, ulong[] op1)
+ {
+ ulong acc = op1[0];
+
+ for (int i = 1; i < op1.Length; i++)
+ {
+ acc = reduceOp(acc, op1[i]);
+ }
+
+ return acc;
+ }
+
public static float AddAcross(float[] op1) => Reduce(Add, op1);
public static float MaxAcross(float[] op1) => Reduce(Max, op1);
@@ -5152,6 +5255,31 @@ private static float Reduce(Func reduceOp, float[] op1)
return acc;
}
+ public static float AddAcrossRecursivePairwise(float[] op1) => ReduceRecursivePairwise(Add, op1);
+
+ private static float ReduceRecursivePairwise(Func reduceOp, float[] op1)
+ {
+ if (op1.Length == 2)
+ {
+ return reduceOp(op1[0], op1[1]);
+ }
+
+ if (op1.Length % 2 != 0)
+ {
+ return float.NaN;
+ }
+
+ float[] l = new float[op1.Length / 2];
+ Array.Copy(op1, 0, l, 0, (op1.Length / 2));
+ float l_reduced = ReduceRecursivePairwise(reduceOp, l);
+
+ float[] r = new float[op1.Length / 2];
+ Array.Copy(op1, (op1.Length / 2), r, 0, (op1.Length / 2));
+ float r_reduced = ReduceRecursivePairwise(reduceOp, r);
+
+ return reduceOp(l_reduced, r_reduced);
+ }
+
public static double AddAcross(double[] op1) => Reduce(Add, op1);
public static double MaxAcross(double[] op1) => Reduce(Max, op1);
@@ -5170,6 +5298,31 @@ private static double Reduce(Func reduceOp, double[] op1
return acc;
}
+ public static double AddAcrossRecursivePairwise(double[] op1) => ReduceRecursivePairwise(Add, op1);
+
+ private static double ReduceRecursivePairwise(Func reduceOp, double[] op1)
+ {
+ if (op1.Length == 2)
+ {
+ return reduceOp(op1[0], op1[1]);
+ }
+
+ if (op1.Length % 2 != 0)
+ {
+ return double.NaN;
+ }
+
+ double[] l = new double[op1.Length / 2];
+ Array.Copy(op1, 0, l, 0, (op1.Length / 2));
+ double l_reduced = ReduceRecursivePairwise(reduceOp, l);
+
+ double[] r = new double[op1.Length / 2];
+ Array.Copy(op1, (op1.Length / 2), r, 0, (op1.Length / 2));
+ double r_reduced = ReduceRecursivePairwise(reduceOp, r);
+
+ return reduceOp(l_reduced, r_reduced);
+ }
+
public static float MaxNumberAcross(float[] op1) => Reduce(MaxNumber, op1);
public static float MinNumberAcross(float[] op1) => Reduce(MinNumber, op1);
diff --git a/src/tests/JIT/HardwareIntrinsics/Arm/Shared/_SveMinimalUnaryOpTestTemplate.template b/src/tests/JIT/HardwareIntrinsics/Arm/Shared/_SveMinimalUnaryOpTestTemplate.template
new file mode 100644
index 0000000000000..782f77de3520e
--- /dev/null
+++ b/src/tests/JIT/HardwareIntrinsics/Arm/Shared/_SveMinimalUnaryOpTestTemplate.template
@@ -0,0 +1,302 @@
+// 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();
+ }
+ 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[] inArray1;
+ private byte[] outArray;
+
+ private GCHandle inHandle1;
+ private GCHandle outHandle;
+
+ private ulong alignment;
+
+ public DataTable({Op1BaseType}[] inArray1, {RetBaseType}[] outArray, int alignment)
+ {
+ int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf<{Op1BaseType}>();
+ int sizeOfoutArray = outArray.Length * Unsafe.SizeOf<{RetBaseType}>();
+ if ((alignment != 64 && alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray)
+ {
+ throw new ArgumentException($"Invalid value of alignment: {alignment}, sizeOfinArray1: {sizeOfinArray1}, sizeOfoutArray: {sizeOfoutArray}");
+ }
+
+ this.inArray1 = new byte[alignment * 2];
+ this.outArray = new byte[alignment * 2];
+
+ this.inHandle1 = GCHandle.Alloc(this.inArray1, 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);
+ }
+
+ public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment);
+ public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment);
+
+ public void Dispose()
+ {
+ inHandle1.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 static TestStruct Create()
+ {
+ var testStruct = new TestStruct();
+
+ for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = {NextValueOp1}; }
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<{Op1VectorType}<{Op1BaseType}>, byte>(ref testStruct._fld1), ref Unsafe.As<{Op1BaseType}, byte>(ref _data1[0]), (uint)Unsafe.SizeOf<{Op1VectorType}<{Op1BaseType}>>());
+
+ return testStruct;
+ }
+
+ public void RunStructFldScenario({TemplateName}UnaryOpTest__{TestName} testClass)
+ {
+ var result = {Isa}.{Method}(_fld1);
+
+ Unsafe.Write(testClass._dataTable.outArrayPtr, result);
+ testClass.ValidateResult(_fld1, 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 {Op1BaseType}[] _data1 = new {Op1BaseType}[Op1ElementCount];
+
+ private {Op1VectorType}<{Op1BaseType}> _fld1;
+
+ private DataTable _dataTable;
+
+ public {TemplateName}UnaryOpTest__{TestName}()
+ {
+ Succeeded = true;
+
+ for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = {NextValueOp1}; }
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<{Op1VectorType}<{Op1BaseType}>, byte>(ref _fld1), ref Unsafe.As<{Op1BaseType}, byte>(ref _data1[0]), (uint)Unsafe.SizeOf<{Op1VectorType}<{Op1BaseType}>>());
+
+ for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = {NextValueOp1}; }
+ _dataTable = new DataTable(_data1, 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.inArray1Ptr)
+ );
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr);
+ }
+
+ public void RunBasicScenario_Load()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load));
+
+ {Op1VectorType}<{Op1BaseType}> loadMask = Sve.CreateTrueMask{Op1BaseType}(SveMaskPattern.All);
+
+ var result = {Isa}.{Method}(
+ {LoadIsa}.Load{Op1VectorType}(loadMask, ({Op1BaseType}*)(_dataTable.inArray1Ptr))
+ );
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(_dataTable.inArray1Ptr, _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}>) })
+ .Invoke(null, new object[] {
+ Unsafe.Read<{Op1VectorType}<{Op1BaseType}>>(_dataTable.inArray1Ptr)
+ });
+
+ Unsafe.Write(_dataTable.outArrayPtr, ({RetVectorType}<{RetBaseType}>)(result));
+ ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr);
+ }
+
+ public void RunLclVarScenario_UnsafeRead()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead));
+
+ var op1 = Unsafe.Read<{Op1VectorType}<{Op1BaseType}>>(_dataTable.inArray1Ptr);
+ var result = {Isa}.{Method}(op1);
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(op1, _dataTable.outArrayPtr);
+ }
+
+ public void RunClassFldScenario()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario));
+
+ var result = {Isa}.{Method}(_fld1);
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(_fld1, _dataTable.outArrayPtr);
+ }
+
+ public void RunStructLclFldScenario()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario));
+
+ var test = TestStruct.Create();
+ var result = {Isa}.{Method}(test._fld1);
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(test._fld1, _dataTable.outArrayPtr);
+ }
+
+ public void RunStructFldScenario()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario));
+
+ var test = TestStruct.Create();
+ test.RunStructFldScenario(this);
+ }
+
+ public void RunUnsupportedScenario()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario));
+
+ bool succeeded = false;
+
+ try
+ {
+ RunBasicScenario_UnsafeRead();
+ }
+ catch (PlatformNotSupportedException)
+ {
+ succeeded = true;
+ }
+
+ if (!succeeded)
+ {
+ Succeeded = false;
+ }
+ }
+
+ private void ValidateResult({Op1VectorType}<{Op1BaseType}> op1, void* result, [CallerMemberName] string method = "")
+ {
+ {Op1BaseType}[] inArray1 = new {Op1BaseType}[Op1ElementCount];
+ {RetBaseType}[] outArray = new {RetBaseType}[RetElementCount];
+
+ Unsafe.WriteUnaligned(ref Unsafe.As<{Op1BaseType}, byte>(ref inArray1[0]), op1);
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<{RetBaseType}, byte>(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf<{RetVectorType}<{RetBaseType}>>());
+
+ ValidateResult(inArray1, outArray, method);
+ }
+
+ private void ValidateResult(void* op1, void* result, [CallerMemberName] string method = "")
+ {
+ {Op1BaseType}[] inArray1 = new {Op1BaseType}[Op1ElementCount];
+ {RetBaseType}[] outArray = new {RetBaseType}[RetElementCount];
+
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<{Op1BaseType}, byte>(ref inArray1[0]), ref Unsafe.AsRef(op1), (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(inArray1, outArray, method);
+ }
+
+ private void ValidateResult({Op1BaseType}[] firstOp, {RetBaseType}[] result, [CallerMemberName] string method = "")
+ {
+ bool succeeded = true;
+
+ {TemplateValidationLogic}
+
+ if (!succeeded)
+ {
+ TestLibrary.TestFramework.LogInformation($"{nameof({Isa})}.{nameof({Isa}.{Method})}<{RetBaseType}>({Op1VectorType}<{Op1BaseType}>): {method} failed:");
+ TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})");
+ TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})");
+ TestLibrary.TestFramework.LogInformation(string.Empty);
+
+ Succeeded = false;
+ }
+ }
+ }
+}
diff --git a/src/tests/JIT/HardwareIntrinsics/Arm/Shared/_SveUnaryOpTestTemplate.template b/src/tests/JIT/HardwareIntrinsics/Arm/Shared/_SveUnaryOpTestTemplate.template
index 557442de4cf0b..119cc5d88cb6f 100644
--- a/src/tests/JIT/HardwareIntrinsics/Arm/Shared/_SveUnaryOpTestTemplate.template
+++ b/src/tests/JIT/HardwareIntrinsics/Arm/Shared/_SveUnaryOpTestTemplate.template
@@ -191,7 +191,7 @@ namespace JIT.HardwareIntrinsics.Arm
{
TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load));
- {Op1VectorType}<{Op1BaseType}> loadMask = Sve.CreateTrueMask{RetBaseType}(SveMaskPattern.All);
+ {Op1VectorType}<{Op1BaseType}> loadMask = Sve.CreateTrueMask{Op1BaseType}(SveMaskPattern.All);
var result = {Isa}.{Method}(
{LoadIsa}.Load{Op1VectorType}(loadMask, ({Op1BaseType}*)(_dataTable.inArray1Ptr))