Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for Sve.UnzipEven/Odd & Sve.ZipHighLow #101294

Merged
merged 5 commits into from
Apr 26, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions src/coreclr/jit/hwintrinsiccodegenarm64.cpp
Original file line number Diff line number Diff line change
@@ -1443,6 +1443,15 @@ void CodeGen::genHWIntrinsic(GenTreeHWIntrinsic* node)
break;
}

case NI_Sve_UnzipEven:
case NI_Sve_UnzipOdd:
case NI_Sve_ZipHigh:
case NI_Sve_ZipLow:
// Use non-predicated version explicitly
GetEmitter()->emitIns_R_R_R(ins, emitSize, targetReg, op1Reg, op2Reg, opt,
INS_SCALABLE_OPTS_UNPREDICATED);
break;

default:
unreached();
}
5 changes: 5 additions & 0 deletions src/coreclr/jit/hwintrinsiclistarm64sve.h
Original file line number Diff line number Diff line change
@@ -64,6 +64,11 @@ HARDWARE_INTRINSIC(Sve, LoadVectorUInt16ZeroExtendToUInt64,
HARDWARE_INTRINSIC(Sve, LoadVectorUInt32ZeroExtendToInt64, -1, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_ld1w, INS_invalid, INS_invalid, INS_invalid}, HW_Category_MemoryLoad, HW_Flag_Scalable|HW_Flag_ExplicitMaskedOperation|HW_Flag_LowMaskedOperation)
HARDWARE_INTRINSIC(Sve, LoadVectorUInt32ZeroExtendToUInt64, -1, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_ld1w, INS_invalid, INS_invalid}, HW_Category_MemoryLoad, HW_Flag_Scalable|HW_Flag_ExplicitMaskedOperation|HW_Flag_LowMaskedOperation)

HARDWARE_INTRINSIC(Sve, UnzipEven, -1, 2, true, {INS_sve_uzp1, INS_sve_uzp1, INS_sve_uzp1, INS_sve_uzp1, INS_sve_uzp1, INS_sve_uzp1, INS_sve_uzp1, INS_sve_uzp1, INS_sve_uzp1, INS_sve_uzp1}, HW_Category_SIMD, HW_Flag_Scalable|HW_Flag_SpecialCodeGen)
HARDWARE_INTRINSIC(Sve, UnzipOdd, -1, 2, true, {INS_sve_uzp2, INS_sve_uzp2, INS_sve_uzp2, INS_sve_uzp2, INS_sve_uzp2, INS_sve_uzp2, INS_sve_uzp2, INS_sve_uzp2, INS_sve_uzp2, INS_sve_uzp2}, HW_Category_SIMD, HW_Flag_Scalable|HW_Flag_SpecialCodeGen)
HARDWARE_INTRINSIC(Sve, ZipHigh, -1, 2, true, {INS_sve_zip2, INS_sve_zip2, INS_sve_zip2, INS_sve_zip2, INS_sve_zip2, INS_sve_zip2, INS_sve_zip2, INS_sve_zip2, INS_sve_zip2, INS_sve_zip2}, HW_Category_SIMD, HW_Flag_Scalable|HW_Flag_SpecialCodeGen)
HARDWARE_INTRINSIC(Sve, ZipLow, -1, 2, true, {INS_sve_zip1, INS_sve_zip1, INS_sve_zip1, INS_sve_zip1, INS_sve_zip1, INS_sve_zip1, INS_sve_zip1, INS_sve_zip1, INS_sve_zip1, INS_sve_zip1}, HW_Category_SIMD, HW_Flag_Scalable|HW_Flag_SpecialCodeGen)


// ***************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************
// ISA Function name SIMD size NumArg EncodesExtraTypeArg Instructions Category Flags
Original file line number Diff line number Diff line change
@@ -806,5 +806,260 @@ internal Arm64() { }
public static unsafe Vector<ulong> LoadVectorUInt32ZeroExtendToUInt64(Vector<ulong> mask, uint* address) { throw new PlatformNotSupportedException(); }


/// UnzipEven : Concatenate even elements from two inputs

/// <summary>
/// svint8_t svuzp1[_s8](svint8_t op1, svint8_t op2)
/// </summary>
public static unsafe Vector<sbyte> UnzipEven(Vector<sbyte> left, Vector<sbyte> right) { throw new PlatformNotSupportedException(); }

/// <summary>
/// svint16_t svuzp1[_s16](svint16_t op1, svint16_t op2)
/// </summary>
public static unsafe Vector<short> UnzipEven(Vector<short> left, Vector<short> right) { throw new PlatformNotSupportedException(); }

/// <summary>
/// svint32_t svuzp1[_s32](svint32_t op1, svint32_t op2)
/// </summary>
public static unsafe Vector<int> UnzipEven(Vector<int> left, Vector<int> right) { throw new PlatformNotSupportedException(); }

/// <summary>
/// svint64_t svuzp1[_s64](svint64_t op1, svint64_t op2)
/// </summary>
public static unsafe Vector<long> UnzipEven(Vector<long> left, Vector<long> right) { throw new PlatformNotSupportedException(); }

/// <summary>
/// svuint8_t svuzp1[_u8](svuint8_t op1, svuint8_t op2)
/// svbool_t svuzp1_b8(svbool_t op1, svbool_t op2)
/// </summary>
public static unsafe Vector<byte> UnzipEven(Vector<byte> left, Vector<byte> right) { throw new PlatformNotSupportedException(); }

/// <summary>
/// svuint16_t svuzp1[_u16](svuint16_t op1, svuint16_t op2)
/// svbool_t svuzp1_b16(svbool_t op1, svbool_t op2)
/// </summary>
public static unsafe Vector<ushort> UnzipEven(Vector<ushort> left, Vector<ushort> right) { throw new PlatformNotSupportedException(); }

/// <summary>
/// svuint32_t svuzp1[_u32](svuint32_t op1, svuint32_t op2)
/// svbool_t svuzp1_b32(svbool_t op1, svbool_t op2)
/// </summary>
public static unsafe Vector<uint> UnzipEven(Vector<uint> left, Vector<uint> right) { throw new PlatformNotSupportedException(); }

/// <summary>
/// svuint64_t svuzp1[_u64](svuint64_t op1, svuint64_t op2)
/// svbool_t svuzp1_b64(svbool_t op1, svbool_t op2)
/// </summary>
public static unsafe Vector<ulong> UnzipEven(Vector<ulong> left, Vector<ulong> right) { throw new PlatformNotSupportedException(); }

/// <summary>
/// svfloat32_t svuzp1[_f32](svfloat32_t op1, svfloat32_t op2)
/// </summary>
public static unsafe Vector<float> UnzipEven(Vector<float> left, Vector<float> right) { throw new PlatformNotSupportedException(); }

/// <summary>
/// svfloat64_t svuzp1[_f64](svfloat64_t op1, svfloat64_t op2)
/// </summary>
public static unsafe Vector<double> UnzipEven(Vector<double> left, Vector<double> right) { throw new PlatformNotSupportedException(); }


/// UnzipOdd : Concatenate odd elements from two inputs

/// <summary>
/// svuint8_t svuzp2[_u8](svuint8_t op1, svuint8_t op2)
/// svbool_t svuzp2_b8(svbool_t op1, svbool_t op2)
/// </summary>
public static unsafe Vector<byte> UnzipOdd(Vector<byte> left, Vector<byte> right) { throw new PlatformNotSupportedException(); }

/// <summary>
/// svfloat64_t svuzp2[_f64](svfloat64_t op1, svfloat64_t op2)
/// </summary>
public static unsafe Vector<double> UnzipOdd(Vector<double> left, Vector<double> right) { throw new PlatformNotSupportedException(); }

/// <summary>
/// svint16_t svuzp2[_s16](svint16_t op1, svint16_t op2)
/// UZP2 Zresult.H, Zop1.H, Zop2.H
/// </summary>
public static unsafe Vector<short> UnzipOdd(Vector<short> left, Vector<short> right) { throw new PlatformNotSupportedException(); }

/// <summary>
/// svint32_t svuzp2[_s32](svint32_t op1, svint32_t op2)
/// </summary>
public static unsafe Vector<int> UnzipOdd(Vector<int> left, Vector<int> right) { throw new PlatformNotSupportedException(); }

/// <summary>
/// svint64_t svuzp2[_s64](svint64_t op1, svint64_t op2)
/// </summary>
public static unsafe Vector<long> UnzipOdd(Vector<long> left, Vector<long> right) { throw new PlatformNotSupportedException(); }

/// <summary>
/// svint8_t svuzp2[_s8](svint8_t op1, svint8_t op2)
/// </summary>
public static unsafe Vector<sbyte> UnzipOdd(Vector<sbyte> left, Vector<sbyte> right) { throw new PlatformNotSupportedException(); }

/// <summary>
/// svfloat32_t svuzp2[_f32](svfloat32_t op1, svfloat32_t op2)
/// </summary>
public static unsafe Vector<float> UnzipOdd(Vector<float> left, Vector<float> right) { throw new PlatformNotSupportedException(); }

/// <summary>
/// svuint16_t svuzp2[_u16](svuint16_t op1, svuint16_t op2)
/// svbool_t svuzp2_b16(svbool_t op1, svbool_t op2)
/// </summary>
public static unsafe Vector<ushort> UnzipOdd(Vector<ushort> left, Vector<ushort> right) { throw new PlatformNotSupportedException(); }

/// <summary>
/// svuint32_t svuzp2[_u32](svuint32_t op1, svuint32_t op2)
/// svbool_t svuzp2_b32(svbool_t op1, svbool_t op2)
/// </summary>
public static unsafe Vector<uint> UnzipOdd(Vector<uint> left, Vector<uint> right) { throw new PlatformNotSupportedException(); }

/// <summary>
/// svuint64_t svuzp2[_u64](svuint64_t op1, svuint64_t op2)
/// svbool_t svuzp2_b64(svbool_t op1, svbool_t op2)
/// </summary>
public static unsafe Vector<ulong> UnzipOdd(Vector<ulong> left, Vector<ulong> right) { throw new PlatformNotSupportedException(); }


/// ZipHigh : Interleave elements from high halves of two inputs

/// <summary>
/// svuint8_t svzip2[_u8](svuint8_t op1, svuint8_t op2)
/// ZIP2 Zresult.B, Zop1.B, Zop2.B
/// svbool_t svzip2_b8(svbool_t op1, svbool_t op2)
/// ZIP2 Presult.B, Pop1.B, Pop2.B
/// </summary>
public static unsafe Vector<byte> ZipHigh(Vector<byte> left, Vector<byte> right) { throw new PlatformNotSupportedException(); }

/// <summary>
/// svfloat64_t svzip2[_f64](svfloat64_t op1, svfloat64_t op2)
/// ZIP2 Zresult.D, Zop1.D, Zop2.D
/// </summary>
public static unsafe Vector<double> ZipHigh(Vector<double> left, Vector<double> right) { throw new PlatformNotSupportedException(); }

/// <summary>
/// svint16_t svzip2[_s16](svint16_t op1, svint16_t op2)
/// ZIP2 Zresult.H, Zop1.H, Zop2.H
/// </summary>
public static unsafe Vector<short> ZipHigh(Vector<short> left, Vector<short> right) { throw new PlatformNotSupportedException(); }

/// <summary>
/// svint32_t svzip2[_s32](svint32_t op1, svint32_t op2)
/// ZIP2 Zresult.S, Zop1.S, Zop2.S
/// </summary>
public static unsafe Vector<int> ZipHigh(Vector<int> left, Vector<int> right) { throw new PlatformNotSupportedException(); }

/// <summary>
/// svint64_t svzip2[_s64](svint64_t op1, svint64_t op2)
/// ZIP2 Zresult.D, Zop1.D, Zop2.D
/// </summary>
public static unsafe Vector<long> ZipHigh(Vector<long> left, Vector<long> right) { throw new PlatformNotSupportedException(); }

/// <summary>
/// svint8_t svzip2[_s8](svint8_t op1, svint8_t op2)
/// ZIP2 Zresult.B, Zop1.B, Zop2.B
/// </summary>
public static unsafe Vector<sbyte> ZipHigh(Vector<sbyte> left, Vector<sbyte> right) { throw new PlatformNotSupportedException(); }

/// <summary>
/// svfloat32_t svzip2[_f32](svfloat32_t op1, svfloat32_t op2)
/// ZIP2 Zresult.S, Zop1.S, Zop2.S
/// </summary>
public static unsafe Vector<float> ZipHigh(Vector<float> left, Vector<float> right) { throw new PlatformNotSupportedException(); }

/// <summary>
/// svuint16_t svzip2[_u16](svuint16_t op1, svuint16_t op2)
/// ZIP2 Zresult.H, Zop1.H, Zop2.H
/// svbool_t svzip2_b16(svbool_t op1, svbool_t op2)
/// ZIP2 Presult.H, Pop1.H, Pop2.H
/// </summary>
public static unsafe Vector<ushort> ZipHigh(Vector<ushort> left, Vector<ushort> right) { throw new PlatformNotSupportedException(); }

/// <summary>
/// svuint32_t svzip2[_u32](svuint32_t op1, svuint32_t op2)
/// ZIP2 Zresult.S, Zop1.S, Zop2.S
/// svbool_t svzip2_b32(svbool_t op1, svbool_t op2)
/// ZIP2 Presult.S, Pop1.S, Pop2.S
/// </summary>
public static unsafe Vector<uint> ZipHigh(Vector<uint> left, Vector<uint> right) { throw new PlatformNotSupportedException(); }

/// <summary>
/// svuint64_t svzip2[_u64](svuint64_t op1, svuint64_t op2)
/// ZIP2 Zresult.D, Zop1.D, Zop2.D
/// svbool_t svzip2_b64(svbool_t op1, svbool_t op2)
/// ZIP2 Presult.D, Pop1.D, Pop2.D
/// </summary>
public static unsafe Vector<ulong> ZipHigh(Vector<ulong> left, Vector<ulong> right) { throw new PlatformNotSupportedException(); }


/// ZipLow : Interleave elements from low halves of two inputs

/// <summary>
/// svuint8_t svzip1[_u8](svuint8_t op1, svuint8_t op2)
/// ZIP1 Zresult.B, Zop1.B, Zop2.B
/// svbool_t svzip1_b8(svbool_t op1, svbool_t op2)
/// ZIP1 Presult.B, Pop1.B, Pop2.B
/// </summary>
public static unsafe Vector<byte> ZipLow(Vector<byte> left, Vector<byte> right) { throw new PlatformNotSupportedException(); }

/// <summary>
/// svfloat64_t svzip1[_f64](svfloat64_t op1, svfloat64_t op2)
/// ZIP1 Zresult.D, Zop1.D, Zop2.D
/// </summary>
public static unsafe Vector<double> ZipLow(Vector<double> left, Vector<double> right) { throw new PlatformNotSupportedException(); }

/// <summary>
/// svint16_t svzip1[_s16](svint16_t op1, svint16_t op2)
/// ZIP1 Zresult.H, Zop1.H, Zop2.H
/// </summary>
public static unsafe Vector<short> ZipLow(Vector<short> left, Vector<short> right) { throw new PlatformNotSupportedException(); }

/// <summary>
/// svint32_t svzip1[_s32](svint32_t op1, svint32_t op2)
/// ZIP1 Zresult.S, Zop1.S, Zop2.S
/// </summary>
public static unsafe Vector<int> ZipLow(Vector<int> left, Vector<int> right) { throw new PlatformNotSupportedException(); }

/// <summary>
/// svint64_t svzip1[_s64](svint64_t op1, svint64_t op2)
/// ZIP1 Zresult.D, Zop1.D, Zop2.D
/// </summary>
public static unsafe Vector<long> ZipLow(Vector<long> left, Vector<long> right) { throw new PlatformNotSupportedException(); }

/// <summary>
/// svint8_t svzip1[_s8](svint8_t op1, svint8_t op2)
/// ZIP1 Zresult.B, Zop1.B, Zop2.B
/// </summary>
public static unsafe Vector<sbyte> ZipLow(Vector<sbyte> left, Vector<sbyte> right) { throw new PlatformNotSupportedException(); }

/// <summary>
/// svfloat32_t svzip1[_f32](svfloat32_t op1, svfloat32_t op2)
/// ZIP1 Zresult.S, Zop1.S, Zop2.S
/// </summary>
public static unsafe Vector<float> ZipLow(Vector<float> left, Vector<float> right) { throw new PlatformNotSupportedException(); }

/// <summary>
/// svuint16_t svzip1[_u16](svuint16_t op1, svuint16_t op2)
/// ZIP1 Zresult.H, Zop1.H, Zop2.H
/// svbool_t svzip1_b16(svbool_t op1, svbool_t op2)
/// ZIP1 Presult.H, Pop1.H, Pop2.H
/// </summary>
public static unsafe Vector<ushort> ZipLow(Vector<ushort> left, Vector<ushort> right) { throw new PlatformNotSupportedException(); }

/// <summary>
/// svuint32_t svzip1[_u32](svuint32_t op1, svuint32_t op2)
/// ZIP1 Zresult.S, Zop1.S, Zop2.S
/// svbool_t svzip1_b32(svbool_t op1, svbool_t op2)
/// ZIP1 Presult.S, Pop1.S, Pop2.S
/// </summary>
public static unsafe Vector<uint> ZipLow(Vector<uint> left, Vector<uint> right) { throw new PlatformNotSupportedException(); }

/// <summary>
/// svuint64_t svzip1[_u64](svuint64_t op1, svuint64_t op2)
/// ZIP1 Zresult.D, Zop1.D, Zop2.D
/// svbool_t svzip1_b64(svbool_t op1, svbool_t op2)
/// ZIP1 Presult.D, Pop1.D, Pop2.D
/// </summary>
public static unsafe Vector<ulong> ZipLow(Vector<ulong> left, Vector<ulong> right) { throw new PlatformNotSupportedException(); }
}
}
Original file line number Diff line number Diff line change
@@ -861,5 +861,287 @@ internal Arm64() { }
public static unsafe Vector<ulong> LoadVectorUInt32ZeroExtendToUInt64(Vector<ulong> mask, uint* address) => LoadVectorUInt32ZeroExtendToUInt64(mask, address);


/// UnzipEven : Concatenate even elements from two inputs

/// <summary>
/// svuint8_t svuzp1[_u8](svuint8_t op1, svuint8_t op2)
/// UZP1 Zresult.B, Zop1.B, Zop2.B
/// svbool_t svuzp1_b8(svbool_t op1, svbool_t op2)
/// UZP1 Presult.B, Pop1.B, Pop2.B
/// </summary>
public static unsafe Vector<byte> UnzipEven(Vector<byte> left, Vector<byte> right) => UnzipEven(left, right);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just realized that zip and unzip instructions operate on both vector and predicate registers. How do we know which one to invoke? Currently, we will always invoke vector variants? @a74nh ?

If we always going to support just the vector version, then please remove the comment for predicate registers.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right now it'll just be the vector variant. If we're using masks then there will be a lot of conversions and the vector version will be used.

Raised a ticket: #101598

In the meantime, is it ok to leave the comment as is?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for opening an issue and yes, ok to keep it as of now.


/// <summary>
/// svfloat64_t svuzp1[_f64](svfloat64_t op1, svfloat64_t op2)
/// UZP1 Zresult.D, Zop1.D, Zop2.D
/// </summary>
public static unsafe Vector<double> UnzipEven(Vector<double> left, Vector<double> right) => UnzipEven(left, right);

/// <summary>
/// svint16_t svuzp1[_s16](svint16_t op1, svint16_t op2)
/// UZP1 Zresult.H, Zop1.H, Zop2.H
/// </summary>
public static unsafe Vector<short> UnzipEven(Vector<short> left, Vector<short> right) => UnzipEven(left, right);

/// <summary>
/// svint32_t svuzp1[_s32](svint32_t op1, svint32_t op2)
/// UZP1 Zresult.S, Zop1.S, Zop2.S
/// </summary>
public static unsafe Vector<int> UnzipEven(Vector<int> left, Vector<int> right) => UnzipEven(left, right);

/// <summary>
/// svint64_t svuzp1[_s64](svint64_t op1, svint64_t op2)
/// UZP1 Zresult.D, Zop1.D, Zop2.D
/// </summary>
public static unsafe Vector<long> UnzipEven(Vector<long> left, Vector<long> right) => UnzipEven(left, right);

/// <summary>
/// svint8_t svuzp1[_s8](svint8_t op1, svint8_t op2)
/// UZP1 Zresult.B, Zop1.B, Zop2.B
/// </summary>
public static unsafe Vector<sbyte> UnzipEven(Vector<sbyte> left, Vector<sbyte> right) => UnzipEven(left, right);

/// <summary>
/// svfloat32_t svuzp1[_f32](svfloat32_t op1, svfloat32_t op2)
/// UZP1 Zresult.S, Zop1.S, Zop2.S
/// </summary>
public static unsafe Vector<float> UnzipEven(Vector<float> left, Vector<float> right) => UnzipEven(left, right);

/// <summary>
/// svuint16_t svuzp1[_u16](svuint16_t op1, svuint16_t op2)
/// UZP1 Zresult.H, Zop1.H, Zop2.H
/// svbool_t svuzp1_b16(svbool_t op1, svbool_t op2)
/// UZP1 Presult.H, Pop1.H, Pop2.H
/// </summary>
public static unsafe Vector<ushort> UnzipEven(Vector<ushort> left, Vector<ushort> right) => UnzipEven(left, right);

/// <summary>
/// svuint32_t svuzp1[_u32](svuint32_t op1, svuint32_t op2)
/// UZP1 Zresult.S, Zop1.S, Zop2.S
/// svbool_t svuzp1_b32(svbool_t op1, svbool_t op2)
/// UZP1 Presult.S, Pop1.S, Pop2.S
/// </summary>
public static unsafe Vector<uint> UnzipEven(Vector<uint> left, Vector<uint> right) => UnzipEven(left, right);

/// <summary>
/// svuint64_t svuzp1[_u64](svuint64_t op1, svuint64_t op2)
/// UZP1 Zresult.D, Zop1.D, Zop2.D
/// svbool_t svuzp1_b64(svbool_t op1, svbool_t op2)
/// UZP1 Presult.D, Pop1.D, Pop2.D
/// </summary>
public static unsafe Vector<ulong> UnzipEven(Vector<ulong> left, Vector<ulong> right) => UnzipEven(left, right);


/// UnzipOdd : Concatenate odd elements from two inputs

/// <summary>
/// svuint8_t svuzp2[_u8](svuint8_t op1, svuint8_t op2)
/// UZP2 Zresult.B, Zop1.B, Zop2.B
/// svbool_t svuzp2_b8(svbool_t op1, svbool_t op2)
/// UZP2 Presult.B, Pop1.B, Pop2.B
/// </summary>
public static unsafe Vector<byte> UnzipOdd(Vector<byte> left, Vector<byte> right) => UnzipOdd(left, right);

/// <summary>
/// svfloat64_t svuzp2[_f64](svfloat64_t op1, svfloat64_t op2)
/// UZP2 Zresult.D, Zop1.D, Zop2.D
/// </summary>
public static unsafe Vector<double> UnzipOdd(Vector<double> left, Vector<double> right) => UnzipOdd(left, right);

/// <summary>
/// svint16_t svuzp2[_s16](svint16_t op1, svint16_t op2)
/// UZP2 Zresult.H, Zop1.H, Zop2.H
/// </summary>
public static unsafe Vector<short> UnzipOdd(Vector<short> left, Vector<short> right) => UnzipOdd(left, right);

/// <summary>
/// svint32_t svuzp2[_s32](svint32_t op1, svint32_t op2)
/// UZP2 Zresult.S, Zop1.S, Zop2.S
/// </summary>
public static unsafe Vector<int> UnzipOdd(Vector<int> left, Vector<int> right) => UnzipOdd(left, right);

/// <summary>
/// svint64_t svuzp2[_s64](svint64_t op1, svint64_t op2)
/// UZP2 Zresult.D, Zop1.D, Zop2.D
/// </summary>
public static unsafe Vector<long> UnzipOdd(Vector<long> left, Vector<long> right) => UnzipOdd(left, right);

/// <summary>
/// svint8_t svuzp2[_s8](svint8_t op1, svint8_t op2)
/// UZP2 Zresult.B, Zop1.B, Zop2.B
/// </summary>
public static unsafe Vector<sbyte> UnzipOdd(Vector<sbyte> left, Vector<sbyte> right) => UnzipOdd(left, right);

/// <summary>
/// svfloat32_t svuzp2[_f32](svfloat32_t op1, svfloat32_t op2)
/// UZP2 Zresult.S, Zop1.S, Zop2.S
/// </summary>
public static unsafe Vector<float> UnzipOdd(Vector<float> left, Vector<float> right) => UnzipOdd(left, right);

/// <summary>
/// svuint16_t svuzp2[_u16](svuint16_t op1, svuint16_t op2)
/// UZP2 Zresult.H, Zop1.H, Zop2.H
/// svbool_t svuzp2_b16(svbool_t op1, svbool_t op2)
/// UZP2 Presult.H, Pop1.H, Pop2.H
/// </summary>
public static unsafe Vector<ushort> UnzipOdd(Vector<ushort> left, Vector<ushort> right) => UnzipOdd(left, right);

/// <summary>
/// svuint32_t svuzp2[_u32](svuint32_t op1, svuint32_t op2)
/// UZP2 Zresult.S, Zop1.S, Zop2.S
/// svbool_t svuzp2_b32(svbool_t op1, svbool_t op2)
/// UZP2 Presult.S, Pop1.S, Pop2.S
/// </summary>
public static unsafe Vector<uint> UnzipOdd(Vector<uint> left, Vector<uint> right) => UnzipOdd(left, right);

/// <summary>
/// svuint64_t svuzp2[_u64](svuint64_t op1, svuint64_t op2)
/// UZP2 Zresult.D, Zop1.D, Zop2.D
/// svbool_t svuzp2_b64(svbool_t op1, svbool_t op2)
/// UZP2 Presult.D, Pop1.D, Pop2.D
/// </summary>
public static unsafe Vector<ulong> UnzipOdd(Vector<ulong> left, Vector<ulong> right) => UnzipOdd(left, right);
/// ZipHigh : Interleave elements from high halves of two inputs

/// <summary>
/// svuint8_t svzip2[_u8](svuint8_t op1, svuint8_t op2)
/// ZIP2 Zresult.B, Zop1.B, Zop2.B
/// svbool_t svzip2_b8(svbool_t op1, svbool_t op2)
/// ZIP2 Presult.B, Pop1.B, Pop2.B
/// </summary>


public static unsafe Vector<byte> ZipHigh(Vector<byte> left, Vector<byte> right) => ZipHigh(left, right);

/// <summary>
/// svfloat64_t svzip2[_f64](svfloat64_t op1, svfloat64_t op2)
/// ZIP2 Zresult.D, Zop1.D, Zop2.D
/// </summary>
public static unsafe Vector<double> ZipHigh(Vector<double> left, Vector<double> right) => ZipHigh(left, right);

/// <summary>
/// svint16_t svzip2[_s16](svint16_t op1, svint16_t op2)
/// ZIP2 Zresult.H, Zop1.H, Zop2.H
/// </summary>
public static unsafe Vector<short> ZipHigh(Vector<short> left, Vector<short> right) => ZipHigh(left, right);

/// <summary>
/// svint32_t svzip2[_s32](svint32_t op1, svint32_t op2)
/// ZIP2 Zresult.S, Zop1.S, Zop2.S
/// </summary>
public static unsafe Vector<int> ZipHigh(Vector<int> left, Vector<int> right) => ZipHigh(left, right);

/// <summary>
/// svint64_t svzip2[_s64](svint64_t op1, svint64_t op2)
/// ZIP2 Zresult.D, Zop1.D, Zop2.D
/// </summary>
public static unsafe Vector<long> ZipHigh(Vector<long> left, Vector<long> right) => ZipHigh(left, right);

/// <summary>
/// svint8_t svzip2[_s8](svint8_t op1, svint8_t op2)
/// ZIP2 Zresult.B, Zop1.B, Zop2.B
/// </summary>
public static unsafe Vector<sbyte> ZipHigh(Vector<sbyte> left, Vector<sbyte> right) => ZipHigh(left, right);

/// <summary>
/// svfloat32_t svzip2[_f32](svfloat32_t op1, svfloat32_t op2)
/// ZIP2 Zresult.S, Zop1.S, Zop2.S
/// </summary>
public static unsafe Vector<float> ZipHigh(Vector<float> left, Vector<float> right) => ZipHigh(left, right);

/// <summary>
/// svuint16_t svzip2[_u16](svuint16_t op1, svuint16_t op2)
/// ZIP2 Zresult.H, Zop1.H, Zop2.H
/// svbool_t svzip2_b16(svbool_t op1, svbool_t op2)
/// ZIP2 Presult.H, Pop1.H, Pop2.H
/// </summary>
public static unsafe Vector<ushort> ZipHigh(Vector<ushort> left, Vector<ushort> right) => ZipHigh(left, right);

/// <summary>
/// svuint32_t svzip2[_u32](svuint32_t op1, svuint32_t op2)
/// ZIP2 Zresult.S, Zop1.S, Zop2.S
/// svbool_t svzip2_b32(svbool_t op1, svbool_t op2)
/// ZIP2 Presult.S, Pop1.S, Pop2.S
/// </summary>
public static unsafe Vector<uint> ZipHigh(Vector<uint> left, Vector<uint> right) => ZipHigh(left, right);

/// <summary>
/// svuint64_t svzip2[_u64](svuint64_t op1, svuint64_t op2)
/// ZIP2 Zresult.D, Zop1.D, Zop2.D
/// svbool_t svzip2_b64(svbool_t op1, svbool_t op2)
/// ZIP2 Presult.D, Pop1.D, Pop2.D
/// </summary>
public static unsafe Vector<ulong> ZipHigh(Vector<ulong> left, Vector<ulong> right) => ZipHigh(left, right);


/// ZipLow : Interleave elements from low halves of two inputs

/// <summary>
/// svuint8_t svzip1[_u8](svuint8_t op1, svuint8_t op2)
/// ZIP1 Zresult.B, Zop1.B, Zop2.B
/// svbool_t svzip1_b8(svbool_t op1, svbool_t op2)
/// ZIP1 Presult.B, Pop1.B, Pop2.B
/// </summary>
public static unsafe Vector<byte> ZipLow(Vector<byte> left, Vector<byte> right) => ZipLow(left, right);

/// <summary>
/// svfloat64_t svzip1[_f64](svfloat64_t op1, svfloat64_t op2)
/// ZIP1 Zresult.D, Zop1.D, Zop2.D
/// </summary>
public static unsafe Vector<double> ZipLow(Vector<double> left, Vector<double> right) => ZipLow(left, right);

/// <summary>
/// svint16_t svzip1[_s16](svint16_t op1, svint16_t op2)
/// ZIP1 Zresult.H, Zop1.H, Zop2.H
/// </summary>
public static unsafe Vector<short> ZipLow(Vector<short> left, Vector<short> right) => ZipLow(left, right);

/// <summary>
/// svint32_t svzip1[_s32](svint32_t op1, svint32_t op2)
/// ZIP1 Zresult.S, Zop1.S, Zop2.S
/// </summary>
public static unsafe Vector<int> ZipLow(Vector<int> left, Vector<int> right) => ZipLow(left, right);

/// <summary>
/// svint64_t svzip1[_s64](svint64_t op1, svint64_t op2)
/// ZIP1 Zresult.D, Zop1.D, Zop2.D
/// </summary>
public static unsafe Vector<long> ZipLow(Vector<long> left, Vector<long> right) => ZipLow(left, right);

/// <summary>
/// svint8_t svzip1[_s8](svint8_t op1, svint8_t op2)
/// ZIP1 Zresult.B, Zop1.B, Zop2.B
/// </summary>
public static unsafe Vector<sbyte> ZipLow(Vector<sbyte> left, Vector<sbyte> right) => ZipLow(left, right);

/// <summary>
/// svfloat32_t svzip1[_f32](svfloat32_t op1, svfloat32_t op2)
/// ZIP1 Zresult.S, Zop1.S, Zop2.S
/// </summary>
public static unsafe Vector<float> ZipLow(Vector<float> left, Vector<float> right) => ZipLow(left, right);

/// <summary>
/// svuint16_t svzip1[_u16](svuint16_t op1, svuint16_t op2)
/// ZIP1 Zresult.H, Zop1.H, Zop2.H
/// svbool_t svzip1_b16(svbool_t op1, svbool_t op2)
/// ZIP1 Presult.H, Pop1.H, Pop2.H
/// </summary>
public static unsafe Vector<ushort> ZipLow(Vector<ushort> left, Vector<ushort> right) => ZipLow(left, right);

/// <summary>
/// svuint32_t svzip1[_u32](svuint32_t op1, svuint32_t op2)
/// ZIP1 Zresult.S, Zop1.S, Zop2.S
/// svbool_t svzip1_b32(svbool_t op1, svbool_t op2)
/// ZIP1 Presult.S, Pop1.S, Pop2.S
/// </summary>
public static unsafe Vector<uint> ZipLow(Vector<uint> left, Vector<uint> right) => ZipLow(left, right);

/// <summary>
/// svuint64_t svzip1[_u64](svuint64_t op1, svuint64_t op2)
/// ZIP1 Zresult.D, Zop1.D, Zop2.D
/// svbool_t svzip1_b64(svbool_t op1, svbool_t op2)
/// ZIP1 Presult.D, Pop1.D, Pop2.D
/// </summary>
public static unsafe Vector<ulong> ZipLow(Vector<ulong> left, Vector<ulong> right) => ZipLow(left, right);
}
}
Original file line number Diff line number Diff line change
@@ -4274,6 +4274,49 @@ internal Arm64() { }
public static unsafe System.Numerics.Vector<long> LoadVectorUInt32ZeroExtendToInt64(System.Numerics.Vector<long> mask, uint* address) { throw null; }
public static unsafe System.Numerics.Vector<ulong> LoadVectorUInt32ZeroExtendToUInt64(System.Numerics.Vector<ulong> mask, uint* address) { throw null; }

public static System.Numerics.Vector<sbyte> UnzipEven(System.Numerics.Vector<sbyte> left, System.Numerics.Vector<sbyte> right) { throw null; }
public static System.Numerics.Vector<short> UnzipEven(System.Numerics.Vector<short> left, System.Numerics.Vector<short> right) { throw null; }
public static System.Numerics.Vector<int> UnzipEven(System.Numerics.Vector<int> left, System.Numerics.Vector<int> right) { throw null; }
public static System.Numerics.Vector<long> UnzipEven(System.Numerics.Vector<long> left, System.Numerics.Vector<long> right) { throw null; }
public static System.Numerics.Vector<byte> UnzipEven(System.Numerics.Vector<byte> left, System.Numerics.Vector<byte> right) { throw null; }
public static System.Numerics.Vector<ushort> UnzipEven(System.Numerics.Vector<ushort> left, System.Numerics.Vector<ushort> right) { throw null; }
public static System.Numerics.Vector<uint> UnzipEven(System.Numerics.Vector<uint> left, System.Numerics.Vector<uint> right) { throw null; }
public static System.Numerics.Vector<ulong> UnzipEven(System.Numerics.Vector<ulong> left, System.Numerics.Vector<ulong> right) { throw null; }
public static System.Numerics.Vector<float> UnzipEven(System.Numerics.Vector<float> left, System.Numerics.Vector<float> right) { throw null; }
public static System.Numerics.Vector<double> UnzipEven(System.Numerics.Vector<double> left, System.Numerics.Vector<double> right) { throw null; }

public static System.Numerics.Vector<byte> UnzipOdd(System.Numerics.Vector<byte> left, System.Numerics.Vector<byte> right) { throw null; }
public static System.Numerics.Vector<double> UnzipOdd(System.Numerics.Vector<double> left, System.Numerics.Vector<double> right) { throw null; }
public static System.Numerics.Vector<short> UnzipOdd(System.Numerics.Vector<short> left, System.Numerics.Vector<short> right) { throw null; }
public static System.Numerics.Vector<int> UnzipOdd(System.Numerics.Vector<int> left, System.Numerics.Vector<int> right) { throw null; }
public static System.Numerics.Vector<long> UnzipOdd(System.Numerics.Vector<long> left, System.Numerics.Vector<long> right) { throw null; }
public static System.Numerics.Vector<sbyte> UnzipOdd(System.Numerics.Vector<sbyte> left, System.Numerics.Vector<sbyte> right) { throw null; }
public static System.Numerics.Vector<float> UnzipOdd(System.Numerics.Vector<float> left, System.Numerics.Vector<float> right) { throw null; }
public static System.Numerics.Vector<ushort> UnzipOdd(System.Numerics.Vector<ushort> left, System.Numerics.Vector<ushort> right) { throw null; }
public static System.Numerics.Vector<uint> UnzipOdd(System.Numerics.Vector<uint> left, System.Numerics.Vector<uint> right) { throw null; }
public static System.Numerics.Vector<ulong> UnzipOdd(System.Numerics.Vector<ulong> left, System.Numerics.Vector<ulong> right) { throw null; }

public static System.Numerics.Vector<byte> ZipHigh(System.Numerics.Vector<byte> left, System.Numerics.Vector<byte> right) { throw null; }
public static System.Numerics.Vector<double> ZipHigh(System.Numerics.Vector<double> left, System.Numerics.Vector<double> right) { throw null; }
public static System.Numerics.Vector<short> ZipHigh(System.Numerics.Vector<short> left, System.Numerics.Vector<short> right) { throw null; }
public static System.Numerics.Vector<int> ZipHigh(System.Numerics.Vector<int> left, System.Numerics.Vector<int> right) { throw null; }
public static System.Numerics.Vector<long> ZipHigh(System.Numerics.Vector<long> left, System.Numerics.Vector<long> right) { throw null; }
public static System.Numerics.Vector<sbyte> ZipHigh(System.Numerics.Vector<sbyte> left, System.Numerics.Vector<sbyte> right) { throw null; }
public static System.Numerics.Vector<float> ZipHigh(System.Numerics.Vector<float> left, System.Numerics.Vector<float> right) { throw null; }
public static System.Numerics.Vector<ushort> ZipHigh(System.Numerics.Vector<ushort> left, System.Numerics.Vector<ushort> right) { throw null; }
public static System.Numerics.Vector<uint> ZipHigh(System.Numerics.Vector<uint> left, System.Numerics.Vector<uint> right) { throw null; }
public static System.Numerics.Vector<ulong> ZipHigh(System.Numerics.Vector<ulong> left, System.Numerics.Vector<ulong> right) { throw null; }

public static System.Numerics.Vector<byte> ZipLow(System.Numerics.Vector<byte> left, System.Numerics.Vector<byte> right) { throw null; }
public static System.Numerics.Vector<double> ZipLow(System.Numerics.Vector<double> left, System.Numerics.Vector<double> right) { throw null; }
public static System.Numerics.Vector<short> ZipLow(System.Numerics.Vector<short> left, System.Numerics.Vector<short> right) { throw null; }
public static System.Numerics.Vector<int> ZipLow(System.Numerics.Vector<int> left, System.Numerics.Vector<int> right) { throw null; }
public static System.Numerics.Vector<long> ZipLow(System.Numerics.Vector<long> left, System.Numerics.Vector<long> right) { throw null; }
public static System.Numerics.Vector<sbyte> ZipLow(System.Numerics.Vector<sbyte> left, System.Numerics.Vector<sbyte> right) { throw null; }
public static System.Numerics.Vector<float> ZipLow(System.Numerics.Vector<float> left, System.Numerics.Vector<float> right) { throw null; }
public static System.Numerics.Vector<ushort> ZipLow(System.Numerics.Vector<ushort> left, System.Numerics.Vector<ushort> right) { throw null; }
public static System.Numerics.Vector<uint> ZipLow(System.Numerics.Vector<uint> left, System.Numerics.Vector<uint> right) { throw null; }
public static System.Numerics.Vector<ulong> ZipLow(System.Numerics.Vector<ulong> left, System.Numerics.Vector<ulong> right) { throw null; }
}

public enum SveMaskPattern : byte

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,327 @@
// 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}BinaryOpTest__{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}BinaryOpTest__{TestName}
{
private struct DataTable
{
private byte[] inArray1;
private byte[] inArray2;
private byte[] outArray;

private GCHandle inHandle1;
private GCHandle inHandle2;
private GCHandle outHandle;

private ulong alignment;

public DataTable({Op1BaseType}[] inArray1, {Op2BaseType}[] inArray2, {RetBaseType}[] outArray, int alignment)
{
int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf<{Op1BaseType}>();
int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf<{Op2BaseType}>();
int sizeOfoutArray = outArray.Length * Unsafe.SizeOf<{RetBaseType}>();
if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray)
{
throw new ArgumentException("Invalid value of alignment");
}

this.inArray1 = new byte[alignment * 2];
this.inArray2 = 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.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned);

this.alignment = (ulong)alignment;

Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef<byte>(inArray1Ptr), ref Unsafe.As<{Op1BaseType}, byte>(ref inArray1[0]), (uint)sizeOfinArray1);
Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef<byte>(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* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment);

public void Dispose()
{
inHandle1.Free();
inHandle2.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()
{
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}>>());
for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = {NextValueOp2}; }
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({TemplateName}BinaryOpTest__{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};

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 {TemplateName}BinaryOpTest__{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 < Op2ElementCount; i++) { _data2[i] = {NextValueOp2}; }
Unsafe.CopyBlockUnaligned(ref Unsafe.As<{Op2VectorType}<{Op2BaseType}>, byte>(ref _fld2), ref Unsafe.As<{Op2BaseType}, byte>(ref _data2[0]), (uint)Unsafe.SizeOf<{Op2VectorType}<{Op2BaseType}>>());

for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = {NextValueOp1}; }
for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = {NextValueOp2}; }
_dataTable = new DataTable(_data1, _data2, 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.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));
Vector<{Op1BaseType}> loadMask = Sve.CreateTrueMask{Op1BaseType}(SveMaskPattern.All);

var result = {Isa}.{Method}(
{LoadIsa}.Load{Op1VectorType}(loadMask, ({Op1BaseType}*)(_dataTable.inArray1Ptr)),
{LoadIsa}.Load{Op2VectorType}(loadMask, ({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({Op2VectorType}<{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();
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();
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, {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<byte>(result), (uint)Unsafe.SizeOf<{RetVectorType}<{RetBaseType}>>());

ValidateResult(inArray1, inArray2, outArray, method);
}

private void ValidateResult(void* op1, void* op2, 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<byte>(op1), (uint)Unsafe.SizeOf<{Op1VectorType}<{Op1BaseType}>>());
Unsafe.CopyBlockUnaligned(ref Unsafe.As<{Op2BaseType}, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(op2), (uint)Unsafe.SizeOf<{Op2VectorType}<{Op2BaseType}>>());
Unsafe.CopyBlockUnaligned(ref Unsafe.As<{RetBaseType}, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), (uint)Unsafe.SizeOf<{RetVectorType}<{RetBaseType}>>());

ValidateResult(inArray1, inArray2, outArray, method);
}

private void ValidateResult({Op1BaseType}[] left, {Op2BaseType}[] right, {RetBaseType}[] result, [CallerMemberName] string method = "")
{
bool succeeded = true;

{TemplateValidationLogic}

if (!succeeded)
{
TestLibrary.TestFramework.LogInformation($"{nameof({Isa})}.{nameof({Isa}.{Method})}<{RetBaseType}>({Op1VectorType}<{Op1BaseType}>, {Op2VectorType}<{Op2BaseType}>): {method} failed:");
TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})");
TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})");
TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})");
TestLibrary.TestFramework.LogInformation(string.Empty);

Succeeded = false;
}
}
}
}