diff options
author | Carol Eidt <carol.eidt@microsoft.com> | 2018-03-20 17:01:14 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-03-20 17:01:14 -0700 |
commit | 0ebc0979a899d2e9da0643e3b5601618bcc3c4eb (patch) | |
tree | c273a5686c6b3a991992c8f97b0c12bff30f7b2d | |
parent | 103fe23ca43b9583f4de41ec3ed7572eef4025d5 (diff) | |
parent | dd96fc5e1eec6b3d14fbf0537f4da36306a7c02a (diff) | |
download | coreclr-0ebc0979a899d2e9da0643e3b5601618bcc3c4eb.tar.gz coreclr-0ebc0979a899d2e9da0643e3b5601618bcc3c4eb.tar.bz2 coreclr-0ebc0979a899d2e9da0643e3b5601618bcc3c4eb.zip |
Merge pull request #16955 from fiigii/moreavx
Implement more AVX/AVX2 intrinsics
69 files changed, 12926 insertions, 5 deletions
diff --git a/src/jit/emitxarch.cpp b/src/jit/emitxarch.cpp index 4e1bec97fb..117bc21c2e 100644 --- a/src/jit/emitxarch.cpp +++ b/src/jit/emitxarch.cpp @@ -223,7 +223,12 @@ bool emitter::IsDstDstSrcAVXInstruction(instruction ins) case INS_unpcklpd: case INS_vinsertf128: case INS_vinserti128: + case INS_vmaskmovps: + case INS_vmaskmovpd: case INS_vperm2i128: + case INS_vperm2f128: + case INS_vpermilpsvar: + case INS_vpermilpdvar: case INS_vpsrlvd: case INS_vpsrlvq: case INS_vpsravd: diff --git a/src/jit/hwintrinsiccodegenxarch.cpp b/src/jit/hwintrinsiccodegenxarch.cpp index 1d2b51ec7e..1d6380ebe0 100644 --- a/src/jit/hwintrinsiccodegenxarch.cpp +++ b/src/jit/hwintrinsiccodegenxarch.cpp @@ -134,7 +134,14 @@ void CodeGen::genHWIntrinsic(GenTreeHWIntrinsic* node) } else if (category == HW_Category_MemoryLoad) { - emit->emitIns_SIMD_R_R_AR(ins, simdSize, targetReg, op1Reg, op2Reg); + if (intrinsicID == NI_AVX_MaskLoad) + { + emit->emitIns_SIMD_R_R_AR(ins, simdSize, targetReg, op2Reg, op1Reg); + } + else + { + emit->emitIns_SIMD_R_R_AR(ins, simdSize, targetReg, op1Reg, op2Reg); + } } else if (Compiler::isImmHWIntrinsic(intrinsicID, op2)) { @@ -1331,7 +1338,6 @@ void CodeGen::genAvxOrAvx2Intrinsic(GenTreeHWIntrinsic* node) if (op1Reg != targetReg) { - instruction ins = Compiler::insOfHWIntrinsic(intrinsicID, node->gtSIMDBaseType); emit->emitIns_R_R(ins, emitTypeSize(TYP_SIMD32), targetReg, op1Reg); } break; diff --git a/src/jit/hwintrinsiclistxarch.h b/src/jit/hwintrinsiclistxarch.h index 7435c286fa..216284f935 100644 --- a/src/jit/hwintrinsiclistxarch.h +++ b/src/jit/hwintrinsiclistxarch.h @@ -333,6 +333,7 @@ HARDWARE_INTRINSIC(AVX_BlendVariable, "BlendVaria HARDWARE_INTRINSIC(AVX_Ceiling, "Ceiling", AVX, 10, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_roundps, INS_roundpd}, HW_Category_SimpleSIMD, HW_Flag_NoRMWSemantics) HARDWARE_INTRINSIC(AVX_BroadcastScalarToVector128, "BroadcastScalarToVector128", AVX, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vbroadcastss, INS_invalid}, HW_Category_MemoryLoad, HW_Flag_NoFlag) HARDWARE_INTRINSIC(AVX_BroadcastScalarToVector256, "BroadcastScalarToVector256", AVX, -1, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vbroadcastss, INS_vbroadcastsd}, HW_Category_MemoryLoad, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AVX_BroadcastVector128ToVector256, "BroadcastVector128ToVector256", AVX, -1, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid,INS_vbroadcastf128,INS_vbroadcastf128}, HW_Category_MemoryLoad, HW_Flag_NoFlag) HARDWARE_INTRINSIC(AVX_Compare, "Compare", AVX, -1, 32, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpps, INS_cmppd}, HW_Category_IMM, HW_Flag_NoFlag) HARDWARE_INTRINSIC(AVX_CompareScalar, "CompareScalar", AVX, -1, 16, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpss, INS_cmpsd}, HW_Category_IMM, HW_Flag_CopyUpperBits) HARDWARE_INTRINSIC(AVX_ConvertToSingle, "ConvertToSingle", AVX, -1, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movss, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoRMWSemantics) @@ -359,9 +360,13 @@ HARDWARE_INTRINSIC(AVX_LoadDquVector256, "LoadDquVec HARDWARE_INTRINSIC(AVX_LoadVector256, "LoadVector256", AVX, -1, 32, 1, {INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movups, INS_movupd}, HW_Category_MemoryLoad, HW_Flag_NoRMWSemantics) HARDWARE_INTRINSIC(AVX_Max, "Max", AVX, -1, 32, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_maxps, INS_maxpd}, HW_Category_SimpleSIMD, HW_Flag_Commutative) HARDWARE_INTRINSIC(AVX_Min, "Min", AVX, -1, 32, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_minps, INS_minpd}, HW_Category_SimpleSIMD, HW_Flag_Commutative) +HARDWARE_INTRINSIC(AVX_MaskLoad, "MaskLoad", AVX, -1, 0, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vmaskmovps,INS_vmaskmovpd}, HW_Category_MemoryLoad, HW_Flag_UnfixedSIMDSize) +HARDWARE_INTRINSIC(AVX_MoveMask, "MoveMask", AVX, -1, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movmskps, INS_movmskpd}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_BaseTypeFromFirstArg) HARDWARE_INTRINSIC(AVX_Multiply, "Multiply", AVX, -1, 32, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_mulps, INS_mulpd}, HW_Category_SimpleSIMD, HW_Flag_Commutative) HARDWARE_INTRINSIC(AVX_Or, "Or", AVX, -1, 32, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_orps, INS_orpd}, HW_Category_SimpleSIMD, HW_Flag_Commutative) HARDWARE_INTRINSIC(AVX_Permute, "Permute", AVX, -1, 0, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vpermilps, INS_vpermilpd}, HW_Category_IMM, HW_Flag_FullRangeIMM|HW_Flag_UnfixedSIMDSize) +HARDWARE_INTRINSIC(AVX_Permute2x128, "Permute2x128", AVX, -1, 32, 3, {INS_vperm2f128,INS_vperm2f128,INS_vperm2f128,INS_vperm2f128,INS_vperm2f128,INS_vperm2f128,INS_vperm2f128,INS_vperm2f128,INS_vperm2f128,INS_vperm2f128}, HW_Category_IMM, HW_Flag_OneTypeGeneric|HW_Flag_FullRangeIMM) +HARDWARE_INTRINSIC(AVX_PermuteVar, "PermuteVar", AVX, -1, 0, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vpermilpsvar,INS_vpermilpdvar}, HW_Category_SimpleSIMD, HW_Flag_UnfixedSIMDSize) HARDWARE_INTRINSIC(AVX_Reciprocal, "Reciprocal", AVX, -1, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_rcpps, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoRMWSemantics) HARDWARE_INTRINSIC(AVX_ReciprocalSqrt, "ReciprocalSqrt", AVX, -1, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_rsqrtps, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoRMWSemantics) HARDWARE_INTRINSIC(AVX_RoundCurrentDirection, "RoundCurrentDirection", AVX, 4, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_roundps, INS_roundpd}, HW_Category_SimpleSIMD, HW_Flag_NoRMWSemantics) @@ -395,17 +400,28 @@ HARDWARE_INTRINSIC(AVX2_Average, "Average", HARDWARE_INTRINSIC(AVX2_BlendVariable, "BlendVariable", AVX2, -1, 32, 3, {INS_vpblendvb, INS_vpblendvb, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) HARDWARE_INTRINSIC(AVX2_BroadcastScalarToVector128, "BroadcastScalarToVector128", AVX2, -1, 16, 1, {INS_vpbroadcastb,INS_vpbroadcastb,INS_vpbroadcastw,INS_vpbroadcastw,INS_vpbroadcastd,INS_vpbroadcastd,INS_vpbroadcastq,INS_vpbroadcastq,INS_vbroadcastss,INS_movddup}, HW_Category_SimpleSIMD, HW_Flag_OneTypeGeneric) HARDWARE_INTRINSIC(AVX2_BroadcastScalarToVector256, "BroadcastScalarToVector256", AVX2, -1, 32, 1, {INS_vpbroadcastb,INS_vpbroadcastb,INS_vpbroadcastw,INS_vpbroadcastw,INS_vpbroadcastd,INS_vpbroadcastd,INS_vpbroadcastq,INS_vpbroadcastq,INS_vbroadcastss,INS_vbroadcastsd}, HW_Category_SimpleSIMD, HW_Flag_OneTypeGeneric) +HARDWARE_INTRINSIC(AVX2_BroadcastVector128ToVector256, "BroadcastVector128ToVector256", AVX2, -1, 32, 1, {INS_vbroadcasti128,INS_vbroadcasti128,INS_vbroadcasti128,INS_vbroadcasti128,INS_vbroadcasti128,INS_vbroadcasti128,INS_vbroadcasti128,INS_vbroadcasti128,INS_invalid,INS_invalid},HW_Category_MemoryLoad, HW_Flag_NoFlag) HARDWARE_INTRINSIC(AVX2_CompareEqual, "CompareEqual", AVX2, -1, 32, 2, {INS_pcmpeqb, INS_pcmpeqb, INS_pcmpeqw, INS_pcmpeqw, INS_pcmpeqd, INS_pcmpeqd, INS_pcmpeqq, INS_pcmpeqq, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_Commutative) HARDWARE_INTRINSIC(AVX2_CompareGreaterThan, "CompareGreaterThan", AVX2, -1, 32, 2, {INS_pcmpgtb, INS_invalid, INS_pcmpgtw, INS_invalid, INS_pcmpgtd, INS_invalid, INS_pcmpgtq, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) HARDWARE_INTRINSIC(AVX2_ExtractVector128, "ExtractVector128", AVX2, -1, 32, -1, {INS_vextracti128,INS_vextracti128,INS_vextracti128,INS_vextracti128,INS_vextracti128,INS_vextracti128,INS_vextracti128,INS_vextracti128,INS_invalid, INS_invalid},HW_Category_IMM, HW_Flag_SpecialImport|HW_Flag_SpecialCodeGen|HW_Flag_FullRangeIMM) +HARDWARE_INTRINSIC(AVX2_ConvertToVector256Int16, "ConvertToVector256Int16", AVX2, -1, 32, 1, {INS_pmovsxbw, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(AVX2_ConvertToVector256UInt16, "ConvertToVector256UInt16", AVX2, -1, 32, 1, {INS_invalid, INS_pmovzxbw, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(AVX2_ConvertToVector256Int32, "ConvertToVector256Int32", AVX2, -1, 32, 1, {INS_pmovsxbd, INS_invalid, INS_pmovsxwd, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(AVX2_ConvertToVector256UInt32, "ConvertToVector256UInt32", AVX2, -1, 32, 1, {INS_invalid, INS_pmovzxbd, INS_invalid, INS_pmovzxwd, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(AVX2_ConvertToVector256Int64, "ConvertToVector256Int64", AVX2, -1, 32, 1, {INS_pmovsxbq, INS_invalid, INS_pmovsxwq, INS_invalid, INS_pmovsxdq, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(AVX2_ConvertToVector256UInt64, "ConvertToVector256UInt64", AVX2, -1, 32, 1, {INS_invalid, INS_pmovzxbq, INS_invalid, INS_pmovzxwq, INS_invalid, INS_pmovzxdq, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_BaseTypeFromFirstArg) HARDWARE_INTRINSIC(AVX2_HorizontalAdd, "HorizontalAdd", AVX2, -1, 32, 2, {INS_invalid, INS_invalid, INS_phaddw, INS_invalid, INS_phaddd, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) HARDWARE_INTRINSIC(AVX2_HorizontalAddSaturate, "HorizontalAddSaturate", AVX2, -1, 32, 2, {INS_invalid, INS_invalid, INS_phaddsw, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) HARDWARE_INTRINSIC(AVX2_HorizontalSubtract, "HorizontalSubtract", AVX2, -1, 32, 2, {INS_invalid, INS_invalid, INS_phsubw, INS_invalid, INS_phsubd, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) HARDWARE_INTRINSIC(AVX2_HorizontalSubtractSaturate, "HorizontalSubtractSaturate", AVX2, -1, 32, 2, {INS_invalid, INS_invalid, INS_phsubsw, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) HARDWARE_INTRINSIC(AVX2_InsertVector128, "InsertVector128", AVX2, -1, 32, 3, {INS_vinserti128,INS_vinserti128,INS_vinserti128,INS_vinserti128,INS_vinserti128,INS_vinserti128,INS_vinserti128,INS_vinserti128,INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_FullRangeIMM|HW_Flag_SpecialCodeGen) HARDWARE_INTRINSIC(AVX2_LoadAlignedVector256NonTemporal, "LoadAlignedVector256NonTemporal", AVX2, -1, 32, 1, {INS_movntdqa, INS_movntdqa, INS_movntdqa, INS_movntdqa, INS_movntdqa, INS_movntdqa, INS_movntdqa, INS_movntdqa, INS_invalid, INS_invalid}, HW_Category_MemoryLoad, HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(AVX2_Max, "Max", AVX2, -1, 32, 2, {INS_pmaxsb, INS_pmaxub, INS_pmaxsw, INS_pmaxuw, INS_pmaxsd, INS_pmaxud, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_Commutative) +HARDWARE_INTRINSIC(AVX2_Min, "Min", AVX2, -1, 32, 2, {INS_pminsb, INS_pminub, INS_pminsw, INS_pminuw, INS_pminsd, INS_pminud, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_Commutative) +HARDWARE_INTRINSIC(AVX2_MoveMask, "MoveMask", AVX2, -1, 32, 1, {INS_pmovmskb, INS_pmovmskb, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_BaseTypeFromFirstArg) HARDWARE_INTRINSIC(AVX2_Multiply, "Multiply", AVX2, -1, 32, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_pmuldq, INS_pmuludq, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_Commutative) HARDWARE_INTRINSIC(AVX2_Or, "Or", AVX2, -1, 32, 2, {INS_por, INS_por, INS_por, INS_por, INS_por, INS_por, INS_por, INS_por, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_Commutative) +HARDWARE_INTRINSIC(AVX2_Permute2x128, "Permute2x128", AVX2, -1, 32, 3, {INS_vperm2i128,INS_vperm2i128,INS_vperm2i128,INS_vperm2i128,INS_vperm2i128,INS_vperm2i128,INS_vperm2i128,INS_vperm2i128,INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_OneTypeGeneric|HW_Flag_FullRangeIMM) HARDWARE_INTRINSIC(AVX2_ShiftLeftLogical, "ShiftLeftLogical", AVX2, -1, 32, 2, {INS_invalid, INS_invalid, INS_psllw, INS_psllw, INS_pslld, INS_pslld, INS_psllq, INS_psllq, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_MaybeIMM|HW_Flag_NoJmpTableIMM|HW_Flag_FullRangeIMM) HARDWARE_INTRINSIC(AVX2_ShiftLeftLogical128BitLane, "ShiftLeftLogical128BitLane", AVX2, -1, 32, 2, {INS_pslldq, INS_pslldq, INS_pslldq, INS_pslldq, INS_pslldq, INS_pslldq, INS_pslldq, INS_pslldq, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_FullRangeIMM) HARDWARE_INTRINSIC(AVX2_ShiftLeftLogicalVariable, "ShiftLeftLogicalVariable", AVX2, -1, 0, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vpsllvd, INS_vpsllvd, INS_vpsllvq, INS_vpsllvq, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_UnfixedSIMDSize|HW_Flag_NoContainment) diff --git a/src/jit/instrsxarch.h b/src/jit/instrsxarch.h index c4caf9ae76..23af97a282 100644 --- a/src/jit/instrsxarch.h +++ b/src/jit/instrsxarch.h @@ -474,8 +474,8 @@ INST3( vpbroadcastb, "pbroadcastb" , 0, IUM_WR, 0, 0, BAD_CODE, BAD_CODE, SS INST3( vpbroadcastw, "pbroadcastw" , 0, IUM_WR, 0, 0, BAD_CODE, BAD_CODE, SSE38(0x79)) // Broadcast int16 value from reg/memory to entire ymm register INST3( vpbroadcastd, "pbroadcastd" , 0, IUM_WR, 0, 0, BAD_CODE, BAD_CODE, SSE38(0x58)) // Broadcast int32 value from reg/memory to entire ymm register INST3( vpbroadcastq, "pbroadcastq" , 0, IUM_WR, 0, 0, BAD_CODE, BAD_CODE, SSE38(0x59)) // Broadcast int64 value from reg/memory to entire ymm register -INST3( vextractf128, "extractf128" , 0, IUM_WR, 0, 0, SSE3A(0x19), BAD_CODE, BAD_CODE) // Extract 128-bit packed floating point values -INST3( vextracti128, "extracti128" , 0, IUM_WR, 0, 0, SSE3A(0x39), BAD_CODE, BAD_CODE) // Extract 128-bit packed integer values +INST3( vextractf128, "extractf128" , 0, IUM_WR, 0, 0, SSE3A(0x19), BAD_CODE, SSE3A(0x19)) // Extract 128-bit packed floating point values +INST3( vextracti128, "extracti128" , 0, IUM_WR, 0, 0, SSE3A(0x39), BAD_CODE, SSE3A(0x39)) // Extract 128-bit packed integer values INST3( vinsertf128, "insertf128" , 0, IUM_WR, 0, 0, BAD_CODE, BAD_CODE, SSE3A(0x18)) // Insert 128-bit packed floating point values INST3( vinserti128, "inserti128" , 0, IUM_WR, 0, 0, BAD_CODE, BAD_CODE, SSE3A(0x38)) // Insert 128-bit packed integer values INST3( vzeroupper, "zeroupper" , 0, IUM_WR, 0, 0, 0xC577F8, BAD_CODE, BAD_CODE) // Zero upper 128-bits of all YMM regs (includes 2-byte fixed VEX prefix) @@ -493,7 +493,13 @@ INST3( vpsllvd, "psllvd" , 0, IUM_WR, 0, 0, BAD_CODE, BAD_CODE, SS INST3( vpsllvq, "psllvq" , 0, IUM_WR, 0, 0, BAD_CODE, BAD_CODE, SSE38(0x47)) // Variable Bit Shift Left Logical INST3( vpermilps, "permilps" , 0, IUM_WR, 0, 0, BAD_CODE, BAD_CODE, SSE3A(0x04)) // Permute In-Lane of Quadruples of Single-Precision Floating-Point Values INST3( vpermilpd, "permilpd" , 0, IUM_WR, 0, 0, BAD_CODE, BAD_CODE, SSE3A(0x05)) // Permute In-Lane of Quadruples of Double-Precision Floating-Point Values - +INST3( vpermilpsvar, "permilpsvar" , 0, IUM_WR, 0, 0, BAD_CODE, BAD_CODE, SSE38(0x0C)) // Permute In-Lane of Quadruples of Single-Precision Floating-Point Values +INST3( vpermilpdvar, "permilpdvar" , 0, IUM_WR, 0, 0, BAD_CODE, BAD_CODE, SSE38(0x0D)) // Permute In-Lane of Quadruples of Double-Precision Floating-Point Values +INST3( vperm2f128, "perm2f128" , 0, IUM_WR, 0, 0, BAD_CODE, BAD_CODE, SSE3A(0x06)) // Permute Floating-Point Values +INST3(vbroadcastf128,"broadcastf128",0, IUM_WR, 0, 0, BAD_CODE, BAD_CODE, SSE38(0x1A)) // Broadcast packed float values read from memory to entire ymm register +INST3(vbroadcasti128,"broadcasti128",0, IUM_WR, 0, 0, BAD_CODE, BAD_CODE, SSE38(0x5A)) // Broadcast packed integer values read from memory to entire ymm register +INST3(vmaskmovps, "maskmovps" ,0, IUM_WR, 0, 0, BAD_CODE, BAD_CODE, SSE38(0x2C)) // Conditional SIMD Packed Loads Float +INST3(vmaskmovpd, "maskmovpd" ,0, IUM_WR, 0, 0, BAD_CODE, BAD_CODE, SSE38(0x2D)) // Conditional SIMD Packed Loads Double INST3(LAST_AVX_INSTRUCTION, "LAST_AVX_INSTRUCTION", 0, IUM_WR, 0, 0, BAD_CODE, BAD_CODE, BAD_CODE) // Scalar instructions in SSE4.2 diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx/Avx_r.csproj b/tests/src/JIT/HardwareIntrinsics/X86/Avx/Avx_r.csproj index 98abca2e19..15fd28eb48 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Avx/Avx_r.csproj +++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx/Avx_r.csproj @@ -130,6 +130,8 @@ <Compile Include="Permute.Double.1.cs" /> <Compile Include="Permute.Single.2.cs" /> <Compile Include="Permute.Double.2.cs" /> + <Compile Include="PermuteVar.Single.cs" /> + <Compile Include="PermuteVar.Double.cs" /> <Compile Include="RoundCurrentDirection.Double.cs" /> <Compile Include="RoundCurrentDirection.Single.cs" /> <Compile Include="RoundToNearestInteger.Double.cs" /> diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx/Avx_ro.csproj b/tests/src/JIT/HardwareIntrinsics/X86/Avx/Avx_ro.csproj index 7b45811695..6551b0ac84 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Avx/Avx_ro.csproj +++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx/Avx_ro.csproj @@ -130,6 +130,8 @@ <Compile Include="Permute.Double.1.cs" /> <Compile Include="Permute.Single.2.cs" /> <Compile Include="Permute.Double.2.cs" /> + <Compile Include="PermuteVar.Single.cs" /> + <Compile Include="PermuteVar.Double.cs" /> <Compile Include="RoundCurrentDirection.Double.cs" /> <Compile Include="RoundCurrentDirection.Single.cs" /> <Compile Include="RoundToNearestInteger.Double.cs" /> diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx/BroadcastVector128ToVector256.cs b/tests/src/JIT/HardwareIntrinsics/X86/Avx/BroadcastVector128ToVector256.cs new file mode 100644 index 0000000000..95e6a9e73f --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx/BroadcastVector128ToVector256.cs @@ -0,0 +1,107 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. +// + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics.X86; +using System.Runtime.Intrinsics; + +namespace IntelHardwareIntrinsicTest +{ + class Program + { + const int Pass = 100; + const int Fail = 0; + + static unsafe int Main(string[] args) + { + int testResult = Pass; + + if (Avx.IsSupported) + { + using (TestTable<float> floatTable = new TestTable<float>(new float[8] { 1, -5, 100, 0, 1, 2, 3, 4 }, new float[8])) + { + var vf = Avx.BroadcastVector128ToVector256((float*)(floatTable.inArrayPtr)); + Unsafe.Write(floatTable.outArrayPtr, vf); + + if (!floatTable.CheckResult((x, y) => BitConverter.SingleToInt32Bits(x) == BitConverter.SingleToInt32Bits(y))) + { + Console.WriteLine("AVX BroadcastVector128ToVector256 failed on float:"); + foreach (var item in floatTable.outArray) + { + Console.Write(item + ", "); + } + Console.WriteLine(); + testResult = Fail; + } + } + + using (TestTable<double> doubleTable = new TestTable<double>(new double[4] { 1, -5, 100, 0}, new double[4])) + { + var vf = Avx.BroadcastVector128ToVector256((double*)(doubleTable.inArrayPtr)); + Unsafe.Write(doubleTable.outArrayPtr, vf); + + if (!doubleTable.CheckResult((x, y) => BitConverter.DoubleToInt64Bits(x) == BitConverter.DoubleToInt64Bits(y))) + { + Console.WriteLine("AVX BroadcastVector128ToVector256 failed on double:"); + foreach (var item in doubleTable.outArray) + { + Console.Write(item + ", "); + } + Console.WriteLine(); + testResult = Fail; + } + } + } + return testResult; + } + + public unsafe struct TestTable<T> : IDisposable where T : struct + { + public T[] inArray; + public T[] outArray; + + public void* inArrayPtr => inHandle.AddrOfPinnedObject().ToPointer(); + public void* outArrayPtr => outHandle.AddrOfPinnedObject().ToPointer(); + + GCHandle inHandle; + GCHandle outHandle; + public TestTable(T[] a, T[] b) + { + this.inArray = a; + this.outArray = b; + + inHandle = GCHandle.Alloc(inArray, GCHandleType.Pinned); + outHandle = GCHandle.Alloc(outArray, GCHandleType.Pinned); + } + public bool CheckResult(Func<T, T, bool> check) + { + for (int i = 0; i < outArray.Length/2; i++) + { + if (!check(inArray[i], outArray[i])) + { + return false; + } + } + for (int i = outArray.Length/2; i < outArray.Length; i++) + { + if (!check(inArray[i - outArray.Length/2], outArray[i])) + { + return false; + } + } + return true; + } + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + } + + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx/BroadcastVector128ToVector256_r.csproj b/tests/src/JIT/HardwareIntrinsics/X86/Avx/BroadcastVector128ToVector256_r.csproj new file mode 100644 index 0000000000..1f4bcd4e36 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx/BroadcastVector128ToVector256_r.csproj @@ -0,0 +1,34 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" /> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> + <SchemaVersion>2.0</SchemaVersion> + <ProjectGuid>{95DFC527-4DC1-495E-97D7-E94EE1F7140D}</ProjectGuid> + <OutputType>Exe</OutputType> + <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> + <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir> + <AllowUnsafeBlocks>true</AllowUnsafeBlocks> + </PropertyGroup> + <!-- Default configurations to help VS understand the configurations --> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "></PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' " /> + <ItemGroup> + <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies"> + <Visible>False</Visible> + </CodeAnalysisDependentAssemblyPaths> + </ItemGroup> + <PropertyGroup> + <DebugType>None</DebugType> + <Optimize></Optimize> + </PropertyGroup> + <ItemGroup> + <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" /> + </ItemGroup> + <ItemGroup> + <Compile Include="BroadcastVector128ToVector256.cs" /> + </ItemGroup> + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" /> + <PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' "></PropertyGroup> +</Project>
\ No newline at end of file diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx/BroadcastVector128ToVector256_ro.csproj b/tests/src/JIT/HardwareIntrinsics/X86/Avx/BroadcastVector128ToVector256_ro.csproj new file mode 100644 index 0000000000..feecc1c334 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx/BroadcastVector128ToVector256_ro.csproj @@ -0,0 +1,34 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" /> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> + <SchemaVersion>2.0</SchemaVersion> + <ProjectGuid>{95DFC527-4DC1-495E-97D7-E94EE1F7140D}</ProjectGuid> + <OutputType>Exe</OutputType> + <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> + <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir> + <AllowUnsafeBlocks>true</AllowUnsafeBlocks> + </PropertyGroup> + <!-- Default configurations to help VS understand the configurations --> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "></PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' " /> + <ItemGroup> + <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies"> + <Visible>False</Visible> + </CodeAnalysisDependentAssemblyPaths> + </ItemGroup> + <PropertyGroup> + <DebugType>None</DebugType> + <Optimize>True</Optimize> + </PropertyGroup> + <ItemGroup> + <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" /> + </ItemGroup> + <ItemGroup> + <Compile Include="BroadcastVector128ToVector256.cs" /> + </ItemGroup> + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" /> + <PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' "></PropertyGroup> +</Project>
\ No newline at end of file diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx/MaskLoad.cs b/tests/src/JIT/HardwareIntrinsics/X86/Avx/MaskLoad.cs new file mode 100644 index 0000000000..2a493e095e --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx/MaskLoad.cs @@ -0,0 +1,140 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. +// + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics.X86; +using System.Runtime.Intrinsics; + +namespace IntelHardwareIntrinsicTest +{ + class Program + { + const int Pass = 100; + const int Fail = 0; + + static unsafe int Main(string[] args) + { + int testResult = Pass; + + if (Avx.IsSupported) + { + using (TestTable<float, uint> floatTable = new TestTable<float, uint>(new float[8] { 1, -5, 100, 0, 1, 2, 3, 4 }, new uint[8] { uint.MaxValue, uint.MaxValue, 0, 0, uint.MaxValue, uint.MaxValue, 0, 0 }, new float[8])) + { + Vector256<float> vf = Avx.MaskLoad((float*)(floatTable.inArrayPtr), Avx.LoadVector256((uint*)(floatTable.maskArrayPtr))); + Unsafe.Write(floatTable.outArrayPtr, vf); + + if (!floatTable.CheckResult((x, m, y) => m == uint.MaxValue ? BitConverter.SingleToInt32Bits(x) == BitConverter.SingleToInt32Bits(y) : BitConverter.SingleToInt32Bits(y) == 0)) + { + Console.WriteLine("AVX MaskLoad failed on float:"); + foreach (var item in floatTable.outArray) + { + Console.Write(item + ", "); + } + Console.WriteLine(); + testResult = Fail; + } + } + + using (TestTable<double, ulong> doubleTable = new TestTable<double, ulong>(new double[4] { 1, -5, 100, 0}, new ulong[4] { 0, ulong.MaxValue, ulong.MaxValue, 0}, new double[4])) + { + Vector256<double> vf = Avx.MaskLoad((double*)(doubleTable.inArrayPtr), Avx.LoadVector256((ulong*)(doubleTable.maskArrayPtr))); + Unsafe.Write(doubleTable.outArrayPtr, vf); + + if (!doubleTable.CheckResult((x, m, y) => m == ulong.MaxValue ? BitConverter.DoubleToInt64Bits(x) == BitConverter.DoubleToInt64Bits(y) : BitConverter.DoubleToInt64Bits(y) == 0)) + { + Console.WriteLine("AVX MaskLoad failed on double:"); + foreach (var item in doubleTable.outArray) + { + Console.Write(item + ", "); + } + Console.WriteLine(); + testResult = Fail; + } + } + + using (TestTable<float, uint> floatTable = new TestTable<float, uint>(new float[4] { 1, -5, 100, 0 }, new uint[4] { uint.MaxValue, 0, 0, uint.MaxValue }, new float[4])) + { + Vector128<float> vf = Avx.MaskLoad((float*)(floatTable.inArrayPtr), Sse2.LoadVector128((uint*)(floatTable.maskArrayPtr))); + Unsafe.Write(floatTable.outArrayPtr, vf); + + if (!floatTable.CheckResult((x, m, y) => m == uint.MaxValue ? BitConverter.SingleToInt32Bits(x) == BitConverter.SingleToInt32Bits(y) : BitConverter.SingleToInt32Bits(y) == 0)) + { + Console.WriteLine("AVX MaskLoad failed on Vector128 float:"); + foreach (var item in floatTable.outArray) + { + Console.Write(item + ", "); + } + Console.WriteLine(); + testResult = Fail; + } + } + + using (TestTable<double, ulong> doubleTable = new TestTable<double, ulong>(new double[2] { 1, -5}, new ulong[2] { 0, ulong.MaxValue}, new double[2])) + { + Vector128<double> vf = Avx.MaskLoad((double*)(doubleTable.inArrayPtr), Sse2.LoadVector128((ulong*)(doubleTable.maskArrayPtr))); + Unsafe.Write(doubleTable.outArrayPtr, vf); + + if (!doubleTable.CheckResult((x, m, y) => m == ulong.MaxValue ? BitConverter.DoubleToInt64Bits(x) == BitConverter.DoubleToInt64Bits(y) : BitConverter.DoubleToInt64Bits(y) == 0)) + { + Console.WriteLine("AVX MaskLoad failed on double:"); + foreach (var item in doubleTable.outArray) + { + Console.Write(item + ", "); + } + Console.WriteLine(); + testResult = Fail; + } + } + } + + return testResult; + } + + public unsafe struct TestTable<T, U> : IDisposable where T : struct + { + public T[] inArray; + public U[] maskArray; + public T[] outArray; + + public void* inArrayPtr => inHandle.AddrOfPinnedObject().ToPointer(); + public void* maskArrayPtr => maskHandle.AddrOfPinnedObject().ToPointer(); + public void* outArrayPtr => outHandle.AddrOfPinnedObject().ToPointer(); + + GCHandle inHandle; + GCHandle maskHandle; + GCHandle outHandle; + public TestTable(T[] a, U[] mask, T[] b) + { + this.inArray = a; + this.maskArray = mask; + this.outArray = b; + + inHandle = GCHandle.Alloc(inArray, GCHandleType.Pinned); + maskHandle = GCHandle.Alloc(maskArray, GCHandleType.Pinned); + outHandle = GCHandle.Alloc(outArray, GCHandleType.Pinned); + } + public bool CheckResult(Func<T, U, T, bool> check) + { + for (int i = 0; i < inArray.Length; i++) + { + if (!check(inArray[i], maskArray[i], outArray[i])) + { + return false; + } + } + return true; + } + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + } + + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx/MaskLoad_r.csproj b/tests/src/JIT/HardwareIntrinsics/X86/Avx/MaskLoad_r.csproj new file mode 100644 index 0000000000..a35fbf8f8a --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx/MaskLoad_r.csproj @@ -0,0 +1,34 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" /> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> + <SchemaVersion>2.0</SchemaVersion> + <ProjectGuid>{95DFC527-4DC1-495E-97D7-E94EE1F7140D}</ProjectGuid> + <OutputType>Exe</OutputType> + <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> + <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir> + <AllowUnsafeBlocks>true</AllowUnsafeBlocks> + </PropertyGroup> + <!-- Default configurations to help VS understand the configurations --> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "></PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' " /> + <ItemGroup> + <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies"> + <Visible>False</Visible> + </CodeAnalysisDependentAssemblyPaths> + </ItemGroup> + <PropertyGroup> + <DebugType>None</DebugType> + <Optimize></Optimize> + </PropertyGroup> + <ItemGroup> + <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" /> + </ItemGroup> + <ItemGroup> + <Compile Include="MaskLoad.cs" /> + </ItemGroup> + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" /> + <PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' "></PropertyGroup> +</Project> diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx/MaskLoad_ro.csproj b/tests/src/JIT/HardwareIntrinsics/X86/Avx/MaskLoad_ro.csproj new file mode 100644 index 0000000000..d0a0a9c518 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx/MaskLoad_ro.csproj @@ -0,0 +1,34 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" /> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> + <SchemaVersion>2.0</SchemaVersion> + <ProjectGuid>{95DFC527-4DC1-495E-97D7-E94EE1F7140D}</ProjectGuid> + <OutputType>Exe</OutputType> + <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> + <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir> + <AllowUnsafeBlocks>true</AllowUnsafeBlocks> + </PropertyGroup> + <!-- Default configurations to help VS understand the configurations --> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "></PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' " /> + <ItemGroup> + <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies"> + <Visible>False</Visible> + </CodeAnalysisDependentAssemblyPaths> + </ItemGroup> + <PropertyGroup> + <DebugType>None</DebugType> + <Optimize>True</Optimize> + </PropertyGroup> + <ItemGroup> + <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" /> + </ItemGroup> + <ItemGroup> + <Compile Include="MaskLoad.cs" /> + </ItemGroup> + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" /> + <PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' "></PropertyGroup> +</Project> diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx/MoveMask.cs b/tests/src/JIT/HardwareIntrinsics/X86/Avx/MoveMask.cs new file mode 100644 index 0000000000..98ad32760b --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx/MoveMask.cs @@ -0,0 +1,77 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. +// + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics.X86; +using System.Runtime.Intrinsics; + +namespace IntelHardwareIntrinsicTest +{ + class Program + { + const int Pass = 100; + const int Fail = 0; + + static unsafe int Main(string[] args) + { + int testResult = Pass; + + if (Avx.IsSupported) + { + using (TestTable<float> floatTable = new TestTable<float>(new float[8] { 1, -5, 100, 0, 1, -5, 100, 0 })) + { + + var vf1 = Unsafe.Read<Vector256<float>>(floatTable.inArray1Ptr); + var res = Avx.MoveMask(vf1); + + if (res != 0b00100010) + { + Console.WriteLine("Avx MoveMask failed on float:"); + Console.WriteLine(res); + testResult = Fail; + } + } + + using (TestTable<double> doubleTable = new TestTable<double>(new double[4] { 1, -5, 1, -5 })) + { + + var vf1 = Unsafe.Read<Vector256<double>>(doubleTable.inArray1Ptr); + var res = Avx.MoveMask(vf1); + + if (res != 0b1010) + { + Console.WriteLine("Avx MoveMask failed on double:"); + Console.WriteLine(res); + testResult = Fail; + } + } + } + + + return testResult; + } + + public unsafe struct TestTable<T> : IDisposable where T : struct + { + public T[] inArray1; + public void* inArray1Ptr => inHandle1.AddrOfPinnedObject().ToPointer(); + GCHandle inHandle1; + + public TestTable(T[] a) + { + this.inArray1 = a; + inHandle1 = GCHandle.Alloc(inArray1, GCHandleType.Pinned); + } + + public void Dispose() + { + inHandle1.Free(); + } + } + + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx/MoveMask_r.csproj b/tests/src/JIT/HardwareIntrinsics/X86/Avx/MoveMask_r.csproj new file mode 100644 index 0000000000..868b0ce2e8 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx/MoveMask_r.csproj @@ -0,0 +1,36 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" /> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> + <SchemaVersion>2.0</SchemaVersion> + <ProjectGuid>{EC7AD883-41EA-4BDC-BFBE-77A78B727D76}</ProjectGuid> + <OutputType>Exe</OutputType> + <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> + <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir> + <AllowUnsafeBlocks>true</AllowUnsafeBlocks> + </PropertyGroup> + <!-- Default configurations to help VS understand the configurations --> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' " /> + <ItemGroup> + <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies"> + <Visible>False</Visible> + </CodeAnalysisDependentAssemblyPaths> + </ItemGroup> + <PropertyGroup> + <DebugType>None</DebugType> + <Optimize>True</Optimize> + </PropertyGroup> + <ItemGroup> + <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" /> + </ItemGroup> + <ItemGroup> + <Compile Include="MoveMask.cs" /> + </ItemGroup> + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" /> + <PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' "> + </PropertyGroup> +</Project>
\ No newline at end of file diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx/MoveMask_ro.csproj b/tests/src/JIT/HardwareIntrinsics/X86/Avx/MoveMask_ro.csproj new file mode 100644 index 0000000000..06ad5dc47f --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx/MoveMask_ro.csproj @@ -0,0 +1,36 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" /> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> + <SchemaVersion>2.0</SchemaVersion> + <ProjectGuid>{4D4CC0B8-3894-4F6F-868B-C93A7B722B5C}</ProjectGuid> + <OutputType>Exe</OutputType> + <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> + <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir> + <AllowUnsafeBlocks>true</AllowUnsafeBlocks> + </PropertyGroup> + <!-- Default configurations to help VS understand the configurations --> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' " /> + <ItemGroup> + <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies"> + <Visible>False</Visible> + </CodeAnalysisDependentAssemblyPaths> + </ItemGroup> + <PropertyGroup> + <DebugType>None</DebugType> + <Optimize>True</Optimize> + </PropertyGroup> + <ItemGroup> + <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" /> + </ItemGroup> + <ItemGroup> + <Compile Include="MoveMask.cs" /> + </ItemGroup> + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" /> + <PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' "> + </PropertyGroup> +</Project> diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx/Permute2x128.Avx.cs b/tests/src/JIT/HardwareIntrinsics/X86/Avx/Permute2x128.Avx.cs new file mode 100644 index 0000000000..598b34d343 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx/Permute2x128.Avx.cs @@ -0,0 +1,24 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; + +namespace JIT.HardwareIntrinsics.X86 +{ + public static partial class Program + { + static Program() + { + TestList = new Dictionary<string, Action>() { + ["Permute2x128.Double.2"] = Permute2x128Double2, + ["Permute2x128.Single.2"] = Permute2x128Single2, + ["Permute2x128.Int32.2"] = Permute2x128Int322, + ["Permute2x128.UInt32.2"] = Permute2x128Int322, + ["Permute2x128.Int64.2"] = Permute2x128Int642, + ["Permute2x128.UInt64.2"] = Permute2x128UInt642, + }; + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx/Permute2x128.Avx_r.csproj b/tests/src/JIT/HardwareIntrinsics/X86/Avx/Permute2x128.Avx_r.csproj new file mode 100644 index 0000000000..8f4ae0493e --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx/Permute2x128.Avx_r.csproj @@ -0,0 +1,46 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" /> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> + <SchemaVersion>2.0</SchemaVersion> + <ProjectGuid>{95DFC527-4DC1-495E-97D7-E94EE1F7140D}</ProjectGuid> + <OutputType>Exe</OutputType> + <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> + <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir> + <AllowUnsafeBlocks>true</AllowUnsafeBlocks> + </PropertyGroup> + <!-- Default configurations to help VS understand the configurations --> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "></PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' " /> + <ItemGroup> + <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies"> + <Visible>False</Visible> + </CodeAnalysisDependentAssemblyPaths> + </ItemGroup> + <PropertyGroup> + <DebugType>None</DebugType> + <Optimize></Optimize> + </PropertyGroup> + <ItemGroup> + <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" /> + </ItemGroup> + <ItemGroup> + <Compile Include="Permute2x128.Single.2.cs" /> + <Compile Include="Permute2x128.Double.2.cs" /> + <Compile Include="Permute2x128.Int32.2.cs" /> + <Compile Include="Permute2x128.UInt32.2.cs" /> + <Compile Include="Permute2x128.Int64.2.cs" /> + <Compile Include="Permute2x128.UInt64.2.cs" /> + <Compile Include="Permute2x128.Avx.cs" /> + <Compile Include="..\Shared\BooleanBinOpTest_DataTable.cs" /> + <Compile Include="..\Shared\BooleanTwoCmpOpTest_DataTable.cs" /> + <Compile Include="..\Shared\Program.cs" /> + <Compile Include="..\Shared\SimpleBinOpTest_DataTable.cs" /> + <Compile Include="..\Shared\SimpleTernOpTest_DataTable.cs" /> + <Compile Include="..\Shared\SimpleUnOpTest_DataTable.cs" /> + </ItemGroup> + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" /> + <PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' "></PropertyGroup> +</Project> diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx/Permute2x128.Avx_ro.csproj b/tests/src/JIT/HardwareIntrinsics/X86/Avx/Permute2x128.Avx_ro.csproj new file mode 100644 index 0000000000..f8bb6bdba9 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx/Permute2x128.Avx_ro.csproj @@ -0,0 +1,46 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" /> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> + <SchemaVersion>2.0</SchemaVersion> + <ProjectGuid>{95DFC527-4DC1-495E-97D7-E94EE1F7140D}</ProjectGuid> + <OutputType>Exe</OutputType> + <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> + <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir> + <AllowUnsafeBlocks>true</AllowUnsafeBlocks> + </PropertyGroup> + <!-- Default configurations to help VS understand the configurations --> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "></PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' " /> + <ItemGroup> + <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies"> + <Visible>False</Visible> + </CodeAnalysisDependentAssemblyPaths> + </ItemGroup> + <PropertyGroup> + <DebugType>None</DebugType> + <Optimize>True</Optimize> + </PropertyGroup> + <ItemGroup> + <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" /> + </ItemGroup> + <ItemGroup> + <Compile Include="Permute2x128.Single.2.cs" /> + <Compile Include="Permute2x128.Double.2.cs" /> + <Compile Include="Permute2x128.Int32.2.cs" /> + <Compile Include="Permute2x128.UInt32.2.cs" /> + <Compile Include="Permute2x128.Int64.2.cs" /> + <Compile Include="Permute2x128.UInt64.2.cs" /> + <Compile Include="Permute2x128.Avx.cs" /> + <Compile Include="..\Shared\BooleanBinOpTest_DataTable.cs" /> + <Compile Include="..\Shared\BooleanTwoCmpOpTest_DataTable.cs" /> + <Compile Include="..\Shared\Program.cs" /> + <Compile Include="..\Shared\SimpleBinOpTest_DataTable.cs" /> + <Compile Include="..\Shared\SimpleTernOpTest_DataTable.cs" /> + <Compile Include="..\Shared\SimpleUnOpTest_DataTable.cs" /> + </ItemGroup> + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" /> + <PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' "></PropertyGroup> +</Project> diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx/Permute2x128.Double.2.cs b/tests/src/JIT/HardwareIntrinsics/X86/Avx/Permute2x128.Double.2.cs new file mode 100644 index 0000000000..3df7e70ea9 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx/Permute2x128.Double.2.cs @@ -0,0 +1,337 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\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.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.X86; + +namespace JIT.HardwareIntrinsics.X86 +{ + public static partial class Program + { + private static void Permute2x128Double2() + { + var test = new SimpleBinaryOpTest__Permute2x128Double2(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + + // Validates basic functionality works, using LoadAligned + test.RunBasicScenario_LoadAligned(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + + // Validates calling via reflection works, using LoadAligned + test.RunReflectionScenario_LoadAligned(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + + // Validates passing a local works, using LoadAligned + test.RunLclVarScenario_LoadAligned(); + } + + // Validates passing the field of a local works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + 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 SimpleBinaryOpTest__Permute2x128Double2 + { + private const int VectorSize = 32; + + private const int Op1ElementCount = VectorSize / sizeof(Double); + private const int Op2ElementCount = VectorSize / sizeof(Double); + private const int RetElementCount = VectorSize / sizeof(Double); + + private static Double[] _data1 = new Double[Op1ElementCount]; + private static Double[] _data2 = new Double[Op2ElementCount]; + + private static Vector256<Double> _clsVar1; + private static Vector256<Double> _clsVar2; + + private Vector256<Double> _fld1; + private Vector256<Double> _fld2; + + private SimpleBinaryOpTest__DataTable<Double, Double, Double> _dataTable; + + static SimpleBinaryOpTest__Permute2x128Double2() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (double)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<Double>, byte>(ref _clsVar1), ref Unsafe.As<Double, byte>(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (double)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<Double>, byte>(ref _clsVar2), ref Unsafe.As<Double, byte>(ref _data2[0]), VectorSize); + } + + public SimpleBinaryOpTest__Permute2x128Double2() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (double)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<Double>, byte>(ref _fld1), ref Unsafe.As<Double, byte>(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (double)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<Double>, byte>(ref _fld2), ref Unsafe.As<Double, byte>(ref _data2[0]), VectorSize); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (double)(random.NextDouble()); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (double)(random.NextDouble()); } + _dataTable = new SimpleBinaryOpTest__DataTable<Double, Double, Double>(_data1, _data2, new Double[RetElementCount], VectorSize); + } + + public bool IsSupported => Avx.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Avx.Permute2x128( + Unsafe.Read<Vector256<Double>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector256<Double>>(_dataTable.inArray2Ptr), + 2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Avx.Permute2x128( + Avx.LoadVector256((Double*)(_dataTable.inArray1Ptr)), + Avx.LoadVector256((Double*)(_dataTable.inArray2Ptr)), + 2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Avx.Permute2x128( + Avx.LoadAlignedVector256((Double*)(_dataTable.inArray1Ptr)), + Avx.LoadAlignedVector256((Double*)(_dataTable.inArray2Ptr)), + 2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Avx).GetMethod(nameof(Avx.Permute2x128)).MakeGenericMethod( new Type[] { typeof(Double) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector256<Double>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector256<Double>>(_dataTable.inArray2Ptr), + (byte)2 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<Double>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Avx).GetMethod(nameof(Avx.Permute2x128)).MakeGenericMethod( new Type[] { typeof(Double) }) + .Invoke(null, new object[] { + Avx.LoadVector256((Double*)(_dataTable.inArray1Ptr)), + Avx.LoadVector256((Double*)(_dataTable.inArray2Ptr)), + (byte)2 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<Double>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Avx).GetMethod(nameof(Avx.Permute2x128)).MakeGenericMethod( new Type[] { typeof(Double) }) + .Invoke(null, new object[] { + Avx.LoadAlignedVector256((Double*)(_dataTable.inArray1Ptr)), + Avx.LoadAlignedVector256((Double*)(_dataTable.inArray2Ptr)), + (byte)2 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<Double>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Avx.Permute2x128( + _clsVar1, + _clsVar2, + 2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read<Vector256<Double>>(_dataTable.inArray1Ptr); + var right = Unsafe.Read<Vector256<Double>>(_dataTable.inArray2Ptr); + var result = Avx.Permute2x128(left, right, 2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Avx.LoadVector256((Double*)(_dataTable.inArray1Ptr)); + var right = Avx.LoadVector256((Double*)(_dataTable.inArray2Ptr)); + var result = Avx.Permute2x128(left, right, 2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Avx.LoadAlignedVector256((Double*)(_dataTable.inArray1Ptr)); + var right = Avx.LoadAlignedVector256((Double*)(_dataTable.inArray2Ptr)); + var result = Avx.Permute2x128(left, right, 2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__Permute2x128Double2(); + var result = Avx.Permute2x128(test._fld1, test._fld2, 2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Avx.Permute2x128(_fld1, _fld2, 2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector256<Double> left, Vector256<Double> right, void* result, [CallerMemberName] string method = "") + { + Double[] inArray1 = new Double[Op1ElementCount]; + Double[] inArray2 = new Double[Op2ElementCount]; + Double[] outArray = new Double[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As<Double, byte>(ref inArray1[0]), left); + Unsafe.WriteUnaligned(ref Unsafe.As<Double, byte>(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Double[] inArray1 = new Double[Op1ElementCount]; + Double[] inArray2 = new Double[Op2ElementCount]; + Double[] outArray = new Double[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Double[] left, Double[] right, Double[] result, [CallerMemberName] string method = "") + { + if (BitConverter.DoubleToInt64Bits(result[0]) != BitConverter.DoubleToInt64Bits(right[0])) + { + Succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (i > 1 ? (BitConverter.DoubleToInt64Bits(result[i]) != BitConverter.DoubleToInt64Bits(left[i - 2])) : (BitConverter.DoubleToInt64Bits(result[i]) != BitConverter.DoubleToInt64Bits(right[i]))) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Avx)}.{nameof(Avx.Permute2x128)}<Double>(Vector256<Double>.2, Vector256<Double>): {method} failed:"); + Console.WriteLine($" left: ({string.Join(", ", left)})"); + Console.WriteLine($" right: ({string.Join(", ", right)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx/Permute2x128.Int32.2.cs b/tests/src/JIT/HardwareIntrinsics/X86/Avx/Permute2x128.Int32.2.cs new file mode 100644 index 0000000000..cb0a2ddb12 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx/Permute2x128.Int32.2.cs @@ -0,0 +1,337 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\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.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.X86; + +namespace JIT.HardwareIntrinsics.X86 +{ + public static partial class Program + { + private static void Permute2x128Int322() + { + var test = new SimpleBinaryOpTest__Permute2x128Int322(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + + // Validates basic functionality works, using LoadAligned + test.RunBasicScenario_LoadAligned(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + + // Validates calling via reflection works, using LoadAligned + test.RunReflectionScenario_LoadAligned(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + + // Validates passing a local works, using LoadAligned + test.RunLclVarScenario_LoadAligned(); + } + + // Validates passing the field of a local works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + 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 SimpleBinaryOpTest__Permute2x128Int322 + { + private const int VectorSize = 32; + + private const int Op1ElementCount = VectorSize / sizeof(Int32); + private const int Op2ElementCount = VectorSize / sizeof(Int32); + private const int RetElementCount = VectorSize / sizeof(Int32); + + private static Int32[] _data1 = new Int32[Op1ElementCount]; + private static Int32[] _data2 = new Int32[Op2ElementCount]; + + private static Vector256<Int32> _clsVar1; + private static Vector256<Int32> _clsVar2; + + private Vector256<Int32> _fld1; + private Vector256<Int32> _fld2; + + private SimpleBinaryOpTest__DataTable<Int32, Int32, Int32> _dataTable; + + static SimpleBinaryOpTest__Permute2x128Int322() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (int)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<Int32>, byte>(ref _clsVar1), ref Unsafe.As<Int32, byte>(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (int)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<Int32>, byte>(ref _clsVar2), ref Unsafe.As<Int32, byte>(ref _data2[0]), VectorSize); + } + + public SimpleBinaryOpTest__Permute2x128Int322() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (int)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<Int32>, byte>(ref _fld1), ref Unsafe.As<Int32, byte>(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (int)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<Int32>, byte>(ref _fld2), ref Unsafe.As<Int32, byte>(ref _data2[0]), VectorSize); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (int)(random.Next(0, int.MaxValue)); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (int)(random.Next(0, int.MaxValue)); } + _dataTable = new SimpleBinaryOpTest__DataTable<Int32, Int32, Int32>(_data1, _data2, new Int32[RetElementCount], VectorSize); + } + + public bool IsSupported => Avx.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Avx.Permute2x128( + Unsafe.Read<Vector256<Int32>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector256<Int32>>(_dataTable.inArray2Ptr), + 2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Avx.Permute2x128( + Avx.LoadVector256((Int32*)(_dataTable.inArray1Ptr)), + Avx.LoadVector256((Int32*)(_dataTable.inArray2Ptr)), + 2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Avx.Permute2x128( + Avx.LoadAlignedVector256((Int32*)(_dataTable.inArray1Ptr)), + Avx.LoadAlignedVector256((Int32*)(_dataTable.inArray2Ptr)), + 2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Avx).GetMethod(nameof(Avx.Permute2x128)).MakeGenericMethod( new Type[] { typeof(Int32) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector256<Int32>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector256<Int32>>(_dataTable.inArray2Ptr), + (byte)2 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<Int32>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Avx).GetMethod(nameof(Avx.Permute2x128)).MakeGenericMethod( new Type[] { typeof(Int32) }) + .Invoke(null, new object[] { + Avx.LoadVector256((Int32*)(_dataTable.inArray1Ptr)), + Avx.LoadVector256((Int32*)(_dataTable.inArray2Ptr)), + (byte)2 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<Int32>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Avx).GetMethod(nameof(Avx.Permute2x128)).MakeGenericMethod( new Type[] { typeof(Int32) }) + .Invoke(null, new object[] { + Avx.LoadAlignedVector256((Int32*)(_dataTable.inArray1Ptr)), + Avx.LoadAlignedVector256((Int32*)(_dataTable.inArray2Ptr)), + (byte)2 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<Int32>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Avx.Permute2x128( + _clsVar1, + _clsVar2, + 2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read<Vector256<Int32>>(_dataTable.inArray1Ptr); + var right = Unsafe.Read<Vector256<Int32>>(_dataTable.inArray2Ptr); + var result = Avx.Permute2x128(left, right, 2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Avx.LoadVector256((Int32*)(_dataTable.inArray1Ptr)); + var right = Avx.LoadVector256((Int32*)(_dataTable.inArray2Ptr)); + var result = Avx.Permute2x128(left, right, 2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Avx.LoadAlignedVector256((Int32*)(_dataTable.inArray1Ptr)); + var right = Avx.LoadAlignedVector256((Int32*)(_dataTable.inArray2Ptr)); + var result = Avx.Permute2x128(left, right, 2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__Permute2x128Int322(); + var result = Avx.Permute2x128(test._fld1, test._fld2, 2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Avx.Permute2x128(_fld1, _fld2, 2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector256<Int32> left, Vector256<Int32> right, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As<Int32, byte>(ref inArray1[0]), left); + Unsafe.WriteUnaligned(ref Unsafe.As<Int32, byte>(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int32, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int32, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int32, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int32, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int32[] left, Int32[] right, Int32[] result, [CallerMemberName] string method = "") + { + if (result[0] != right[0]) + { + Succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (i > 3 ? (result[i] != left[i - 4]) : (result[i] != right[i])) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Avx)}.{nameof(Avx.Permute2x128)}<Int32>(Vector256<Int32>.2, Vector256<Int32>): {method} failed:"); + Console.WriteLine($" left: ({string.Join(", ", left)})"); + Console.WriteLine($" right: ({string.Join(", ", right)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx/Permute2x128.Int64.2.cs b/tests/src/JIT/HardwareIntrinsics/X86/Avx/Permute2x128.Int64.2.cs new file mode 100644 index 0000000000..ddbcaa8c6c --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx/Permute2x128.Int64.2.cs @@ -0,0 +1,337 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\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.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.X86; + +namespace JIT.HardwareIntrinsics.X86 +{ + public static partial class Program + { + private static void Permute2x128Int642() + { + var test = new SimpleBinaryOpTest__Permute2x128Int642(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + + // Validates basic functionality works, using LoadAligned + test.RunBasicScenario_LoadAligned(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + + // Validates calling via reflection works, using LoadAligned + test.RunReflectionScenario_LoadAligned(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + + // Validates passing a local works, using LoadAligned + test.RunLclVarScenario_LoadAligned(); + } + + // Validates passing the field of a local works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + 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 SimpleBinaryOpTest__Permute2x128Int642 + { + private const int VectorSize = 32; + + private const int Op1ElementCount = VectorSize / sizeof(Int64); + private const int Op2ElementCount = VectorSize / sizeof(Int64); + private const int RetElementCount = VectorSize / sizeof(Int64); + + private static Int64[] _data1 = new Int64[Op1ElementCount]; + private static Int64[] _data2 = new Int64[Op2ElementCount]; + + private static Vector256<Int64> _clsVar1; + private static Vector256<Int64> _clsVar2; + + private Vector256<Int64> _fld1; + private Vector256<Int64> _fld2; + + private SimpleBinaryOpTest__DataTable<Int64, Int64, Int64> _dataTable; + + static SimpleBinaryOpTest__Permute2x128Int642() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (long)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<Int64>, byte>(ref _clsVar1), ref Unsafe.As<Int64, byte>(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (long)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<Int64>, byte>(ref _clsVar2), ref Unsafe.As<Int64, byte>(ref _data2[0]), VectorSize); + } + + public SimpleBinaryOpTest__Permute2x128Int642() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (long)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<Int64>, byte>(ref _fld1), ref Unsafe.As<Int64, byte>(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (long)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<Int64>, byte>(ref _fld2), ref Unsafe.As<Int64, byte>(ref _data2[0]), VectorSize); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (long)(random.Next(0, int.MaxValue)); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (long)(random.Next(0, int.MaxValue)); } + _dataTable = new SimpleBinaryOpTest__DataTable<Int64, Int64, Int64>(_data1, _data2, new Int64[RetElementCount], VectorSize); + } + + public bool IsSupported => Avx.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Avx.Permute2x128( + Unsafe.Read<Vector256<Int64>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector256<Int64>>(_dataTable.inArray2Ptr), + 2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Avx.Permute2x128( + Avx.LoadVector256((Int64*)(_dataTable.inArray1Ptr)), + Avx.LoadVector256((Int64*)(_dataTable.inArray2Ptr)), + 2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Avx.Permute2x128( + Avx.LoadAlignedVector256((Int64*)(_dataTable.inArray1Ptr)), + Avx.LoadAlignedVector256((Int64*)(_dataTable.inArray2Ptr)), + 2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Avx).GetMethod(nameof(Avx.Permute2x128)).MakeGenericMethod( new Type[] { typeof(Int64) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector256<Int64>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector256<Int64>>(_dataTable.inArray2Ptr), + (byte)2 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<Int64>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Avx).GetMethod(nameof(Avx.Permute2x128)).MakeGenericMethod( new Type[] { typeof(Int64) }) + .Invoke(null, new object[] { + Avx.LoadVector256((Int64*)(_dataTable.inArray1Ptr)), + Avx.LoadVector256((Int64*)(_dataTable.inArray2Ptr)), + (byte)2 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<Int64>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Avx).GetMethod(nameof(Avx.Permute2x128)).MakeGenericMethod( new Type[] { typeof(Int64) }) + .Invoke(null, new object[] { + Avx.LoadAlignedVector256((Int64*)(_dataTable.inArray1Ptr)), + Avx.LoadAlignedVector256((Int64*)(_dataTable.inArray2Ptr)), + (byte)2 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<Int64>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Avx.Permute2x128( + _clsVar1, + _clsVar2, + 2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read<Vector256<Int64>>(_dataTable.inArray1Ptr); + var right = Unsafe.Read<Vector256<Int64>>(_dataTable.inArray2Ptr); + var result = Avx.Permute2x128(left, right, 2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Avx.LoadVector256((Int64*)(_dataTable.inArray1Ptr)); + var right = Avx.LoadVector256((Int64*)(_dataTable.inArray2Ptr)); + var result = Avx.Permute2x128(left, right, 2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Avx.LoadAlignedVector256((Int64*)(_dataTable.inArray1Ptr)); + var right = Avx.LoadAlignedVector256((Int64*)(_dataTable.inArray2Ptr)); + var result = Avx.Permute2x128(left, right, 2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__Permute2x128Int642(); + var result = Avx.Permute2x128(test._fld1, test._fld2, 2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Avx.Permute2x128(_fld1, _fld2, 2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector256<Int64> left, Vector256<Int64> right, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As<Int64, byte>(ref inArray1[0]), left); + Unsafe.WriteUnaligned(ref Unsafe.As<Int64, byte>(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int64, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int64, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int64, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int64, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int64[] left, Int64[] right, Int64[] result, [CallerMemberName] string method = "") + { + if (result[0] != right[0]) + { + Succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (i > 1 ? (result[i] != left[i - 2]) : (result[i] != right[i])) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Avx)}.{nameof(Avx.Permute2x128)}<Int64>(Vector256<Int64>.2, Vector256<Int64>): {method} failed:"); + Console.WriteLine($" left: ({string.Join(", ", left)})"); + Console.WriteLine($" right: ({string.Join(", ", right)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx/Permute2x128.Single.2.cs b/tests/src/JIT/HardwareIntrinsics/X86/Avx/Permute2x128.Single.2.cs new file mode 100644 index 0000000000..bcec95d79c --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx/Permute2x128.Single.2.cs @@ -0,0 +1,337 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\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.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.X86; + +namespace JIT.HardwareIntrinsics.X86 +{ + public static partial class Program + { + private static void Permute2x128Single2() + { + var test = new SimpleBinaryOpTest__Permute2x128Single2(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + + // Validates basic functionality works, using LoadAligned + test.RunBasicScenario_LoadAligned(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + + // Validates calling via reflection works, using LoadAligned + test.RunReflectionScenario_LoadAligned(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + + // Validates passing a local works, using LoadAligned + test.RunLclVarScenario_LoadAligned(); + } + + // Validates passing the field of a local works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + 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 SimpleBinaryOpTest__Permute2x128Single2 + { + private const int VectorSize = 32; + + private const int Op1ElementCount = VectorSize / sizeof(Single); + private const int Op2ElementCount = VectorSize / sizeof(Single); + private const int RetElementCount = VectorSize / sizeof(Single); + + private static Single[] _data1 = new Single[Op1ElementCount]; + private static Single[] _data2 = new Single[Op2ElementCount]; + + private static Vector256<Single> _clsVar1; + private static Vector256<Single> _clsVar2; + + private Vector256<Single> _fld1; + private Vector256<Single> _fld2; + + private SimpleBinaryOpTest__DataTable<Single, Single, Single> _dataTable; + + static SimpleBinaryOpTest__Permute2x128Single2() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (float)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<Single>, byte>(ref _clsVar1), ref Unsafe.As<Single, byte>(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (float)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<Single>, byte>(ref _clsVar2), ref Unsafe.As<Single, byte>(ref _data2[0]), VectorSize); + } + + public SimpleBinaryOpTest__Permute2x128Single2() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (float)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<Single>, byte>(ref _fld1), ref Unsafe.As<Single, byte>(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (float)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<Single>, byte>(ref _fld2), ref Unsafe.As<Single, byte>(ref _data2[0]), VectorSize); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (float)(random.NextDouble()); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (float)(random.NextDouble()); } + _dataTable = new SimpleBinaryOpTest__DataTable<Single, Single, Single>(_data1, _data2, new Single[RetElementCount], VectorSize); + } + + public bool IsSupported => Avx.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Avx.Permute2x128( + Unsafe.Read<Vector256<Single>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector256<Single>>(_dataTable.inArray2Ptr), + 2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Avx.Permute2x128( + Avx.LoadVector256((Single*)(_dataTable.inArray1Ptr)), + Avx.LoadVector256((Single*)(_dataTable.inArray2Ptr)), + 2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Avx.Permute2x128( + Avx.LoadAlignedVector256((Single*)(_dataTable.inArray1Ptr)), + Avx.LoadAlignedVector256((Single*)(_dataTable.inArray2Ptr)), + 2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Avx).GetMethod(nameof(Avx.Permute2x128)).MakeGenericMethod( new Type[] { typeof(Single) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector256<Single>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector256<Single>>(_dataTable.inArray2Ptr), + (byte)2 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<Single>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Avx).GetMethod(nameof(Avx.Permute2x128)).MakeGenericMethod( new Type[] { typeof(Single) }) + .Invoke(null, new object[] { + Avx.LoadVector256((Single*)(_dataTable.inArray1Ptr)), + Avx.LoadVector256((Single*)(_dataTable.inArray2Ptr)), + (byte)2 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<Single>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Avx).GetMethod(nameof(Avx.Permute2x128)).MakeGenericMethod( new Type[] { typeof(Single) }) + .Invoke(null, new object[] { + Avx.LoadAlignedVector256((Single*)(_dataTable.inArray1Ptr)), + Avx.LoadAlignedVector256((Single*)(_dataTable.inArray2Ptr)), + (byte)2 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<Single>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Avx.Permute2x128( + _clsVar1, + _clsVar2, + 2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read<Vector256<Single>>(_dataTable.inArray1Ptr); + var right = Unsafe.Read<Vector256<Single>>(_dataTable.inArray2Ptr); + var result = Avx.Permute2x128(left, right, 2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Avx.LoadVector256((Single*)(_dataTable.inArray1Ptr)); + var right = Avx.LoadVector256((Single*)(_dataTable.inArray2Ptr)); + var result = Avx.Permute2x128(left, right, 2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Avx.LoadAlignedVector256((Single*)(_dataTable.inArray1Ptr)); + var right = Avx.LoadAlignedVector256((Single*)(_dataTable.inArray2Ptr)); + var result = Avx.Permute2x128(left, right, 2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__Permute2x128Single2(); + var result = Avx.Permute2x128(test._fld1, test._fld2, 2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Avx.Permute2x128(_fld1, _fld2, 2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector256<Single> left, Vector256<Single> right, void* result, [CallerMemberName] string method = "") + { + Single[] inArray1 = new Single[Op1ElementCount]; + Single[] inArray2 = new Single[Op2ElementCount]; + Single[] outArray = new Single[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As<Single, byte>(ref inArray1[0]), left); + Unsafe.WriteUnaligned(ref Unsafe.As<Single, byte>(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Single, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Single[] inArray1 = new Single[Op1ElementCount]; + Single[] inArray2 = new Single[Op2ElementCount]; + Single[] outArray = new Single[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Single, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Single, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Single, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Single[] left, Single[] right, Single[] result, [CallerMemberName] string method = "") + { + if (BitConverter.SingleToInt32Bits(result[0]) != BitConverter.SingleToInt32Bits(right[0])) + { + Succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (i > 3 ? (BitConverter.SingleToInt32Bits(result[i]) != BitConverter.SingleToInt32Bits(left[i - 4])) : (BitConverter.SingleToInt32Bits(result[i]) != BitConverter.SingleToInt32Bits(right[i]))) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Avx)}.{nameof(Avx.Permute2x128)}<Single>(Vector256<Single>.2, Vector256<Single>): {method} failed:"); + Console.WriteLine($" left: ({string.Join(", ", left)})"); + Console.WriteLine($" right: ({string.Join(", ", right)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx/Permute2x128.UInt32.2.cs b/tests/src/JIT/HardwareIntrinsics/X86/Avx/Permute2x128.UInt32.2.cs new file mode 100644 index 0000000000..751d0a4fe7 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx/Permute2x128.UInt32.2.cs @@ -0,0 +1,337 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\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.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.X86; + +namespace JIT.HardwareIntrinsics.X86 +{ + public static partial class Program + { + private static void Permute2x128UInt322() + { + var test = new SimpleBinaryOpTest__Permute2x128UInt322(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + + // Validates basic functionality works, using LoadAligned + test.RunBasicScenario_LoadAligned(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + + // Validates calling via reflection works, using LoadAligned + test.RunReflectionScenario_LoadAligned(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + + // Validates passing a local works, using LoadAligned + test.RunLclVarScenario_LoadAligned(); + } + + // Validates passing the field of a local works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + 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 SimpleBinaryOpTest__Permute2x128UInt322 + { + private const int VectorSize = 32; + + private const int Op1ElementCount = VectorSize / sizeof(UInt32); + private const int Op2ElementCount = VectorSize / sizeof(UInt32); + private const int RetElementCount = VectorSize / sizeof(UInt32); + + private static UInt32[] _data1 = new UInt32[Op1ElementCount]; + private static UInt32[] _data2 = new UInt32[Op2ElementCount]; + + private static Vector256<UInt32> _clsVar1; + private static Vector256<UInt32> _clsVar2; + + private Vector256<UInt32> _fld1; + private Vector256<UInt32> _fld2; + + private SimpleBinaryOpTest__DataTable<UInt32, UInt32, UInt32> _dataTable; + + static SimpleBinaryOpTest__Permute2x128UInt322() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (uint)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<UInt32>, byte>(ref _clsVar1), ref Unsafe.As<UInt32, byte>(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (uint)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<UInt32>, byte>(ref _clsVar2), ref Unsafe.As<UInt32, byte>(ref _data2[0]), VectorSize); + } + + public SimpleBinaryOpTest__Permute2x128UInt322() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (uint)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<UInt32>, byte>(ref _fld1), ref Unsafe.As<UInt32, byte>(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (uint)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<UInt32>, byte>(ref _fld2), ref Unsafe.As<UInt32, byte>(ref _data2[0]), VectorSize); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (uint)(random.Next(0, int.MaxValue)); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (uint)(random.Next(0, int.MaxValue)); } + _dataTable = new SimpleBinaryOpTest__DataTable<UInt32, UInt32, UInt32>(_data1, _data2, new UInt32[RetElementCount], VectorSize); + } + + public bool IsSupported => Avx.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Avx.Permute2x128( + Unsafe.Read<Vector256<UInt32>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector256<UInt32>>(_dataTable.inArray2Ptr), + 2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Avx.Permute2x128( + Avx.LoadVector256((UInt32*)(_dataTable.inArray1Ptr)), + Avx.LoadVector256((UInt32*)(_dataTable.inArray2Ptr)), + 2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Avx.Permute2x128( + Avx.LoadAlignedVector256((UInt32*)(_dataTable.inArray1Ptr)), + Avx.LoadAlignedVector256((UInt32*)(_dataTable.inArray2Ptr)), + 2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Avx).GetMethod(nameof(Avx.Permute2x128)).MakeGenericMethod( new Type[] { typeof(UInt32) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector256<UInt32>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector256<UInt32>>(_dataTable.inArray2Ptr), + (byte)2 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<UInt32>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Avx).GetMethod(nameof(Avx.Permute2x128)).MakeGenericMethod( new Type[] { typeof(UInt32) }) + .Invoke(null, new object[] { + Avx.LoadVector256((UInt32*)(_dataTable.inArray1Ptr)), + Avx.LoadVector256((UInt32*)(_dataTable.inArray2Ptr)), + (byte)2 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<UInt32>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Avx).GetMethod(nameof(Avx.Permute2x128)).MakeGenericMethod( new Type[] { typeof(UInt32) }) + .Invoke(null, new object[] { + Avx.LoadAlignedVector256((UInt32*)(_dataTable.inArray1Ptr)), + Avx.LoadAlignedVector256((UInt32*)(_dataTable.inArray2Ptr)), + (byte)2 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<UInt32>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Avx.Permute2x128( + _clsVar1, + _clsVar2, + 2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read<Vector256<UInt32>>(_dataTable.inArray1Ptr); + var right = Unsafe.Read<Vector256<UInt32>>(_dataTable.inArray2Ptr); + var result = Avx.Permute2x128(left, right, 2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Avx.LoadVector256((UInt32*)(_dataTable.inArray1Ptr)); + var right = Avx.LoadVector256((UInt32*)(_dataTable.inArray2Ptr)); + var result = Avx.Permute2x128(left, right, 2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Avx.LoadAlignedVector256((UInt32*)(_dataTable.inArray1Ptr)); + var right = Avx.LoadAlignedVector256((UInt32*)(_dataTable.inArray2Ptr)); + var result = Avx.Permute2x128(left, right, 2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__Permute2x128UInt322(); + var result = Avx.Permute2x128(test._fld1, test._fld2, 2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Avx.Permute2x128(_fld1, _fld2, 2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector256<UInt32> left, Vector256<UInt32> right, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As<UInt32, byte>(ref inArray1[0]), left); + Unsafe.WriteUnaligned(ref Unsafe.As<UInt32, byte>(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt32, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt32, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt32, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt32, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt32[] left, UInt32[] right, UInt32[] result, [CallerMemberName] string method = "") + { + if (result[0] != right[0]) + { + Succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (i > 3 ? (result[i] != left[i - 4]) : (result[i] != right[i])) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Avx)}.{nameof(Avx.Permute2x128)}<UInt32>(Vector256<UInt32>.2, Vector256<UInt32>): {method} failed:"); + Console.WriteLine($" left: ({string.Join(", ", left)})"); + Console.WriteLine($" right: ({string.Join(", ", right)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx/Permute2x128.UInt64.2.cs b/tests/src/JIT/HardwareIntrinsics/X86/Avx/Permute2x128.UInt64.2.cs new file mode 100644 index 0000000000..305b3a8c20 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx/Permute2x128.UInt64.2.cs @@ -0,0 +1,337 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\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.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.X86; + +namespace JIT.HardwareIntrinsics.X86 +{ + public static partial class Program + { + private static void Permute2x128UInt642() + { + var test = new SimpleBinaryOpTest__Permute2x128UInt642(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + + // Validates basic functionality works, using LoadAligned + test.RunBasicScenario_LoadAligned(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + + // Validates calling via reflection works, using LoadAligned + test.RunReflectionScenario_LoadAligned(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + + // Validates passing a local works, using LoadAligned + test.RunLclVarScenario_LoadAligned(); + } + + // Validates passing the field of a local works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + 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 SimpleBinaryOpTest__Permute2x128UInt642 + { + private const int VectorSize = 32; + + private const int Op1ElementCount = VectorSize / sizeof(UInt64); + private const int Op2ElementCount = VectorSize / sizeof(UInt64); + private const int RetElementCount = VectorSize / sizeof(UInt64); + + private static UInt64[] _data1 = new UInt64[Op1ElementCount]; + private static UInt64[] _data2 = new UInt64[Op2ElementCount]; + + private static Vector256<UInt64> _clsVar1; + private static Vector256<UInt64> _clsVar2; + + private Vector256<UInt64> _fld1; + private Vector256<UInt64> _fld2; + + private SimpleBinaryOpTest__DataTable<UInt64, UInt64, UInt64> _dataTable; + + static SimpleBinaryOpTest__Permute2x128UInt642() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (ulong)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<UInt64>, byte>(ref _clsVar1), ref Unsafe.As<UInt64, byte>(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (ulong)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<UInt64>, byte>(ref _clsVar2), ref Unsafe.As<UInt64, byte>(ref _data2[0]), VectorSize); + } + + public SimpleBinaryOpTest__Permute2x128UInt642() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (ulong)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<UInt64>, byte>(ref _fld1), ref Unsafe.As<UInt64, byte>(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (ulong)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<UInt64>, byte>(ref _fld2), ref Unsafe.As<UInt64, byte>(ref _data2[0]), VectorSize); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (ulong)(random.Next(0, int.MaxValue)); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (ulong)(random.Next(0, int.MaxValue)); } + _dataTable = new SimpleBinaryOpTest__DataTable<UInt64, UInt64, UInt64>(_data1, _data2, new UInt64[RetElementCount], VectorSize); + } + + public bool IsSupported => Avx.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Avx.Permute2x128( + Unsafe.Read<Vector256<UInt64>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector256<UInt64>>(_dataTable.inArray2Ptr), + 2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Avx.Permute2x128( + Avx.LoadVector256((UInt64*)(_dataTable.inArray1Ptr)), + Avx.LoadVector256((UInt64*)(_dataTable.inArray2Ptr)), + 2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Avx.Permute2x128( + Avx.LoadAlignedVector256((UInt64*)(_dataTable.inArray1Ptr)), + Avx.LoadAlignedVector256((UInt64*)(_dataTable.inArray2Ptr)), + 2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Avx).GetMethod(nameof(Avx.Permute2x128)).MakeGenericMethod( new Type[] { typeof(UInt64) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector256<UInt64>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector256<UInt64>>(_dataTable.inArray2Ptr), + (byte)2 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<UInt64>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Avx).GetMethod(nameof(Avx.Permute2x128)).MakeGenericMethod( new Type[] { typeof(UInt64) }) + .Invoke(null, new object[] { + Avx.LoadVector256((UInt64*)(_dataTable.inArray1Ptr)), + Avx.LoadVector256((UInt64*)(_dataTable.inArray2Ptr)), + (byte)2 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<UInt64>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Avx).GetMethod(nameof(Avx.Permute2x128)).MakeGenericMethod( new Type[] { typeof(UInt64) }) + .Invoke(null, new object[] { + Avx.LoadAlignedVector256((UInt64*)(_dataTable.inArray1Ptr)), + Avx.LoadAlignedVector256((UInt64*)(_dataTable.inArray2Ptr)), + (byte)2 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<UInt64>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Avx.Permute2x128( + _clsVar1, + _clsVar2, + 2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read<Vector256<UInt64>>(_dataTable.inArray1Ptr); + var right = Unsafe.Read<Vector256<UInt64>>(_dataTable.inArray2Ptr); + var result = Avx.Permute2x128(left, right, 2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Avx.LoadVector256((UInt64*)(_dataTable.inArray1Ptr)); + var right = Avx.LoadVector256((UInt64*)(_dataTable.inArray2Ptr)); + var result = Avx.Permute2x128(left, right, 2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Avx.LoadAlignedVector256((UInt64*)(_dataTable.inArray1Ptr)); + var right = Avx.LoadAlignedVector256((UInt64*)(_dataTable.inArray2Ptr)); + var result = Avx.Permute2x128(left, right, 2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__Permute2x128UInt642(); + var result = Avx.Permute2x128(test._fld1, test._fld2, 2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Avx.Permute2x128(_fld1, _fld2, 2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector256<UInt64> left, Vector256<UInt64> right, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray1 = new UInt64[Op1ElementCount]; + UInt64[] inArray2 = new UInt64[Op2ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As<UInt64, byte>(ref inArray1[0]), left); + Unsafe.WriteUnaligned(ref Unsafe.As<UInt64, byte>(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt64, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray1 = new UInt64[Op1ElementCount]; + UInt64[] inArray2 = new UInt64[Op2ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt64, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt64, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt64, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt64[] left, UInt64[] right, UInt64[] result, [CallerMemberName] string method = "") + { + if (result[0] != right[0]) + { + Succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (i > 1 ? (result[i] != left[i - 2]) : (result[i] != right[i])) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Avx)}.{nameof(Avx.Permute2x128)}<UInt64>(Vector256<UInt64>.2, Vector256<UInt64>): {method} failed:"); + Console.WriteLine($" left: ({string.Join(", ", left)})"); + Console.WriteLine($" right: ({string.Join(", ", right)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx/PermuteVar.Double.cs b/tests/src/JIT/HardwareIntrinsics/X86/Avx/PermuteVar.Double.cs new file mode 100644 index 0000000000..f9171d8e02 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx/PermuteVar.Double.cs @@ -0,0 +1,330 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\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.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.X86; + +namespace JIT.HardwareIntrinsics.X86 +{ + public static partial class Program + { + private static void PermuteVarDouble() + { + var test = new SimpleBinaryOpTest__PermuteVarDouble(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + + // Validates basic functionality works, using LoadAligned + test.RunBasicScenario_LoadAligned(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + + // Validates calling via reflection works, using LoadAligned + test.RunReflectionScenario_LoadAligned(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + + // Validates passing a local works, using LoadAligned + test.RunLclVarScenario_LoadAligned(); + } + + // Validates passing the field of a local works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + 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 SimpleBinaryOpTest__PermuteVarDouble + { + private static readonly int LargestVectorSize = 32; + + private static readonly int Op1ElementCount = Unsafe.SizeOf<Vector256<Double>>() / sizeof(Double); + private static readonly int Op2ElementCount = Unsafe.SizeOf<Vector256<Double>>() / sizeof(Double); + private static readonly int RetElementCount = Unsafe.SizeOf<Vector256<Double>>() / sizeof(Double); + + private static Double[] _data1 = new Double[Op1ElementCount]; + private static Double[] _data2 = new Double[Op2ElementCount]; + + private static Vector256<Double> _clsVar1; + private static Vector256<Double> _clsVar2; + + private Vector256<Double> _fld1; + private Vector256<Double> _fld2; + + private SimpleBinaryOpTest__DataTable<Double, Double, Double> _dataTable; + + static SimpleBinaryOpTest__PermuteVarDouble() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (double)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<Double>, byte>(ref _clsVar1), ref Unsafe.As<Double, byte>(ref _data1[0]), (uint)Unsafe.SizeOf<Vector256<Double>>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = BitConverter.Int64BitsToDouble(1); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<Double>, byte>(ref _clsVar2), ref Unsafe.As<Double, byte>(ref _data2[0]), (uint)Unsafe.SizeOf<Vector256<Double>>()); + } + + public SimpleBinaryOpTest__PermuteVarDouble() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (double)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<Double>, byte>(ref _fld1), ref Unsafe.As<Double, byte>(ref _data1[0]), (uint)Unsafe.SizeOf<Vector256<Double>>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = BitConverter.Int64BitsToDouble(1); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<Double>, byte>(ref _fld2), ref Unsafe.As<Double, byte>(ref _data2[0]), (uint)Unsafe.SizeOf<Vector256<Double>>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (double)(random.NextDouble()); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = BitConverter.Int64BitsToDouble(1); } + _dataTable = new SimpleBinaryOpTest__DataTable<Double, Double, Double>(_data1, _data2, new Double[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => Avx.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Avx.PermuteVar( + Unsafe.Read<Vector256<Double>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector256<Double>>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Avx.PermuteVar( + Avx.LoadVector256((Double*)(_dataTable.inArray1Ptr)), + Avx.LoadVector256((Double*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Avx.PermuteVar( + Avx.LoadAlignedVector256((Double*)(_dataTable.inArray1Ptr)), + Avx.LoadAlignedVector256((Double*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Avx).GetMethod(nameof(Avx.PermuteVar), new Type[] { typeof(Vector256<Double>), typeof(Vector256<Double>) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector256<Double>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector256<Double>>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<Double>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Avx).GetMethod(nameof(Avx.PermuteVar), new Type[] { typeof(Vector256<Double>), typeof(Vector256<Double>) }) + .Invoke(null, new object[] { + Avx.LoadVector256((Double*)(_dataTable.inArray1Ptr)), + Avx.LoadVector256((Double*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<Double>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Avx).GetMethod(nameof(Avx.PermuteVar), new Type[] { typeof(Vector256<Double>), typeof(Vector256<Double>) }) + .Invoke(null, new object[] { + Avx.LoadAlignedVector256((Double*)(_dataTable.inArray1Ptr)), + Avx.LoadAlignedVector256((Double*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<Double>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Avx.PermuteVar( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read<Vector256<Double>>(_dataTable.inArray1Ptr); + var right = Unsafe.Read<Vector256<Double>>(_dataTable.inArray2Ptr); + var result = Avx.PermuteVar(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Avx.LoadVector256((Double*)(_dataTable.inArray1Ptr)); + var right = Avx.LoadVector256((Double*)(_dataTable.inArray2Ptr)); + var result = Avx.PermuteVar(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Avx.LoadAlignedVector256((Double*)(_dataTable.inArray1Ptr)); + var right = Avx.LoadAlignedVector256((Double*)(_dataTable.inArray2Ptr)); + var result = Avx.PermuteVar(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__PermuteVarDouble(); + var result = Avx.PermuteVar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Avx.PermuteVar(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector256<Double> left, Vector256<Double> right, void* result, [CallerMemberName] string method = "") + { + Double[] inArray1 = new Double[Op1ElementCount]; + Double[] inArray2 = new Double[Op2ElementCount]; + Double[] outArray = new Double[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As<Double, byte>(ref inArray1[0]), left); + Unsafe.WriteUnaligned(ref Unsafe.As<Double, byte>(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), (uint)Unsafe.SizeOf<Vector256<Double>>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Double[] inArray1 = new Double[Op1ElementCount]; + Double[] inArray2 = new Double[Op2ElementCount]; + Double[] outArray = new Double[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), (uint)Unsafe.SizeOf<Vector256<Double>>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), (uint)Unsafe.SizeOf<Vector256<Double>>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), (uint)Unsafe.SizeOf<Vector256<Double>>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Double[] left, Double[] right, Double[] result, [CallerMemberName] string method = "") + { + if (BitConverter.DoubleToInt64Bits(left[0]) != BitConverter.DoubleToInt64Bits(result[0])) + { + Succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (i > 1 ? (BitConverter.DoubleToInt64Bits(left[2]) != BitConverter.DoubleToInt64Bits(result[i])) : (BitConverter.DoubleToInt64Bits(left[0]) != BitConverter.DoubleToInt64Bits(result[i]))) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Avx)}.{nameof(Avx.PermuteVar)}<Double>(Vector256<Double>, Vector256<Double>): {method} failed:"); + Console.WriteLine($" left: ({string.Join(", ", left)})"); + Console.WriteLine($" right: ({string.Join(", ", right)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx/PermuteVar.Single.cs b/tests/src/JIT/HardwareIntrinsics/X86/Avx/PermuteVar.Single.cs new file mode 100644 index 0000000000..24e5bb021d --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx/PermuteVar.Single.cs @@ -0,0 +1,330 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\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.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.X86; + +namespace JIT.HardwareIntrinsics.X86 +{ + public static partial class Program + { + private static void PermuteVarSingle() + { + var test = new SimpleBinaryOpTest__PermuteVarSingle(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + + // Validates basic functionality works, using LoadAligned + test.RunBasicScenario_LoadAligned(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + + // Validates calling via reflection works, using LoadAligned + test.RunReflectionScenario_LoadAligned(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + + // Validates passing a local works, using LoadAligned + test.RunLclVarScenario_LoadAligned(); + } + + // Validates passing the field of a local works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + 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 SimpleBinaryOpTest__PermuteVarSingle + { + private static readonly int LargestVectorSize = 32; + + private static readonly int Op1ElementCount = Unsafe.SizeOf<Vector256<Single>>() / sizeof(Single); + private static readonly int Op2ElementCount = Unsafe.SizeOf<Vector256<Single>>() / sizeof(Single); + private static readonly int RetElementCount = Unsafe.SizeOf<Vector256<Single>>() / sizeof(Single); + + private static Single[] _data1 = new Single[Op1ElementCount]; + private static Single[] _data2 = new Single[Op2ElementCount]; + + private static Vector256<Single> _clsVar1; + private static Vector256<Single> _clsVar2; + + private Vector256<Single> _fld1; + private Vector256<Single> _fld2; + + private SimpleBinaryOpTest__DataTable<Single, Single, Single> _dataTable; + + static SimpleBinaryOpTest__PermuteVarSingle() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (float)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<Single>, byte>(ref _clsVar1), ref Unsafe.As<Single, byte>(ref _data1[0]), (uint)Unsafe.SizeOf<Vector256<Single>>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = BitConverter.Int32BitsToSingle(1); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<Single>, byte>(ref _clsVar2), ref Unsafe.As<Single, byte>(ref _data2[0]), (uint)Unsafe.SizeOf<Vector256<Single>>()); + } + + public SimpleBinaryOpTest__PermuteVarSingle() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (float)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<Single>, byte>(ref _fld1), ref Unsafe.As<Single, byte>(ref _data1[0]), (uint)Unsafe.SizeOf<Vector256<Single>>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = BitConverter.Int32BitsToSingle(1); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<Single>, byte>(ref _fld2), ref Unsafe.As<Single, byte>(ref _data2[0]), (uint)Unsafe.SizeOf<Vector256<Single>>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (float)(random.NextDouble()); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = BitConverter.Int32BitsToSingle(1); } + _dataTable = new SimpleBinaryOpTest__DataTable<Single, Single, Single>(_data1, _data2, new Single[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => Avx.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Avx.PermuteVar( + Unsafe.Read<Vector256<Single>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector256<Single>>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Avx.PermuteVar( + Avx.LoadVector256((Single*)(_dataTable.inArray1Ptr)), + Avx.LoadVector256((Single*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Avx.PermuteVar( + Avx.LoadAlignedVector256((Single*)(_dataTable.inArray1Ptr)), + Avx.LoadAlignedVector256((Single*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Avx).GetMethod(nameof(Avx.PermuteVar), new Type[] { typeof(Vector256<Single>), typeof(Vector256<Single>) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector256<Single>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector256<Single>>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<Single>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Avx).GetMethod(nameof(Avx.PermuteVar), new Type[] { typeof(Vector256<Single>), typeof(Vector256<Single>) }) + .Invoke(null, new object[] { + Avx.LoadVector256((Single*)(_dataTable.inArray1Ptr)), + Avx.LoadVector256((Single*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<Single>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Avx).GetMethod(nameof(Avx.PermuteVar), new Type[] { typeof(Vector256<Single>), typeof(Vector256<Single>) }) + .Invoke(null, new object[] { + Avx.LoadAlignedVector256((Single*)(_dataTable.inArray1Ptr)), + Avx.LoadAlignedVector256((Single*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<Single>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Avx.PermuteVar( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read<Vector256<Single>>(_dataTable.inArray1Ptr); + var right = Unsafe.Read<Vector256<Single>>(_dataTable.inArray2Ptr); + var result = Avx.PermuteVar(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Avx.LoadVector256((Single*)(_dataTable.inArray1Ptr)); + var right = Avx.LoadVector256((Single*)(_dataTable.inArray2Ptr)); + var result = Avx.PermuteVar(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Avx.LoadAlignedVector256((Single*)(_dataTable.inArray1Ptr)); + var right = Avx.LoadAlignedVector256((Single*)(_dataTable.inArray2Ptr)); + var result = Avx.PermuteVar(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__PermuteVarSingle(); + var result = Avx.PermuteVar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Avx.PermuteVar(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector256<Single> left, Vector256<Single> right, void* result, [CallerMemberName] string method = "") + { + Single[] inArray1 = new Single[Op1ElementCount]; + Single[] inArray2 = new Single[Op2ElementCount]; + Single[] outArray = new Single[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As<Single, byte>(ref inArray1[0]), left); + Unsafe.WriteUnaligned(ref Unsafe.As<Single, byte>(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Single, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), (uint)Unsafe.SizeOf<Vector256<Single>>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Single[] inArray1 = new Single[Op1ElementCount]; + Single[] inArray2 = new Single[Op2ElementCount]; + Single[] outArray = new Single[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Single, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), (uint)Unsafe.SizeOf<Vector256<Single>>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Single, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), (uint)Unsafe.SizeOf<Vector256<Single>>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Single, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), (uint)Unsafe.SizeOf<Vector256<Single>>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Single[] left, Single[] right, Single[] result, [CallerMemberName] string method = "") + { + if (BitConverter.SingleToInt32Bits(left[1]) != BitConverter.SingleToInt32Bits(result[0])) + { + Succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (i > 3 ? (BitConverter.SingleToInt32Bits(left[5]) != BitConverter.SingleToInt32Bits(result[i])) : (BitConverter.SingleToInt32Bits(left[1]) != BitConverter.SingleToInt32Bits(result[i]))) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Avx)}.{nameof(Avx.PermuteVar)}<Single>(Vector256<Single>, Vector256<Single>): {method} failed:"); + Console.WriteLine($" left: ({string.Join(", ", left)})"); + Console.WriteLine($" right: ({string.Join(", ", right)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx/Program.Avx.cs b/tests/src/JIT/HardwareIntrinsics/X86/Avx/Program.Avx.cs index 1bf4389d94..dbaa1a4912 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Avx/Program.Avx.cs +++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx/Program.Avx.cs @@ -115,6 +115,8 @@ namespace JIT.HardwareIntrinsics.X86 ["Permute.Double.1"] = PermuteDouble1, ["Permute.Single.2"] = PermuteSingle2, ["Permute.Double.2"] = PermuteDouble2, + ["PermuteVar.Single"] = PermuteVarSingle, + ["PermuteVar.Double"] = PermuteVarDouble, ["RoundCurrentDirection.Double"] = RoundCurrentDirectionDouble, ["RoundCurrentDirection.Single"] = RoundCurrentDirectionSingle, ["RoundToNearestInteger.Double"] = RoundToNearestIntegerDouble, diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx2/Avx2_r.csproj b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/Avx2_r.csproj index 027236a269..bc465abb83 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Avx2/Avx2_r.csproj +++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/Avx2_r.csproj @@ -119,6 +119,18 @@ <Compile Include="InsertVector128.UInt32.1.Load.cs" /> <Compile Include="InsertVector128.Int64.1.Load.cs" /> <Compile Include="InsertVector128.UInt64.1.Load.cs" /> + <Compile Include="Max.Byte.cs" /> + <Compile Include="Max.Int16.cs" /> + <Compile Include="Max.Int32.cs" /> + <Compile Include="Max.SByte.cs" /> + <Compile Include="Max.UInt16.cs" /> + <Compile Include="Max.UInt32.cs" /> + <Compile Include="Min.Byte.cs" /> + <Compile Include="Min.Int16.cs" /> + <Compile Include="Min.Int32.cs" /> + <Compile Include="Min.SByte.cs" /> + <Compile Include="Min.UInt16.cs" /> + <Compile Include="Min.UInt32.cs" /> <Compile Include="Or.Byte.cs" /> <Compile Include="Or.Int16.cs" /> <Compile Include="Or.Int32.cs" /> @@ -127,6 +139,10 @@ <Compile Include="Or.UInt16.cs" /> <Compile Include="Or.UInt32.cs" /> <Compile Include="Or.UInt64.cs" /> + <Compile Include="Permute2x128.Int32.2.cs" /> + <Compile Include="Permute2x128.UInt32.2.cs" /> + <Compile Include="Permute2x128.Int64.2.cs" /> + <Compile Include="Permute2x128.UInt64.2.cs" /> <Compile Include="ShiftLeftLogical.Int16.1.cs" /> <Compile Include="ShiftLeftLogical.UInt16.1.cs" /> <Compile Include="ShiftLeftLogical.Int32.1.cs" /> diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx2/Avx2_ro.csproj b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/Avx2_ro.csproj index 7eb8667ead..55ddee102a 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Avx2/Avx2_ro.csproj +++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/Avx2_ro.csproj @@ -119,6 +119,18 @@ <Compile Include="InsertVector128.UInt32.1.Load.cs" /> <Compile Include="InsertVector128.Int64.1.Load.cs" /> <Compile Include="InsertVector128.UInt64.1.Load.cs" /> + <Compile Include="Max.Byte.cs" /> + <Compile Include="Max.Int16.cs" /> + <Compile Include="Max.Int32.cs" /> + <Compile Include="Max.SByte.cs" /> + <Compile Include="Max.UInt16.cs" /> + <Compile Include="Max.UInt32.cs" /> + <Compile Include="Min.Byte.cs" /> + <Compile Include="Min.Int16.cs" /> + <Compile Include="Min.Int32.cs" /> + <Compile Include="Min.SByte.cs" /> + <Compile Include="Min.UInt16.cs" /> + <Compile Include="Min.UInt32.cs" /> <Compile Include="Or.Byte.cs" /> <Compile Include="Or.Int16.cs" /> <Compile Include="Or.Int32.cs" /> @@ -127,6 +139,10 @@ <Compile Include="Or.UInt16.cs" /> <Compile Include="Or.UInt32.cs" /> <Compile Include="Or.UInt64.cs" /> + <Compile Include="Permute2x128.Int32.2.cs" /> + <Compile Include="Permute2x128.UInt32.2.cs" /> + <Compile Include="Permute2x128.Int64.2.cs" /> + <Compile Include="Permute2x128.UInt64.2.cs" /> <Compile Include="ShiftLeftLogical.Int16.1.cs" /> <Compile Include="ShiftLeftLogical.UInt16.1.cs" /> <Compile Include="ShiftLeftLogical.Int32.1.cs" /> diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx2/BroadcastVector128ToVector256.cs b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/BroadcastVector128ToVector256.cs new file mode 100644 index 0000000000..6a0e45ec7a --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/BroadcastVector128ToVector256.cs @@ -0,0 +1,141 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. +// + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics.X86; +using System.Runtime.Intrinsics; + +namespace IntelHardwareIntrinsicTest +{ + class Program + { + const int Pass = 100; + const int Fail = 0; + + static unsafe int Main(string[] args) + { + int testResult = Pass; + + if (Avx2.IsSupported) + { + using (TestTable<int> intTable = new TestTable<int>(new int[8] { 1, -5, 100, 0, 1, 2, 3, 4 }, new int[8])) + { + var vf = Avx2.BroadcastVector128ToVector256((int*)(intTable.inArrayPtr)); + Unsafe.Write(intTable.outArrayPtr, vf); + + if (!intTable.CheckResult((x, y) => x == y)) + { + Console.WriteLine("Avx2 BroadcastVector128ToVector256 failed on int:"); + foreach (var item in intTable.outArray) + { + Console.Write(item + ", "); + } + Console.WriteLine(); + testResult = Fail; + } + } + + using (TestTable<uint> uintTable = new TestTable<uint>(new uint[8] { 1, 5, 100, 0, 1, 2, 3, 4 }, new uint[8])) + { + var vf = Avx2.BroadcastVector128ToVector256((uint*)(uintTable.inArrayPtr)); + Unsafe.Write(uintTable.outArrayPtr, vf); + + if (!uintTable.CheckResult((x, y) => x == y)) + { + Console.WriteLine("Avx2 BroadcastVector128ToVector256 failed on uint:"); + foreach (var item in uintTable.outArray) + { + Console.Write(item + ", "); + } + Console.WriteLine(); + testResult = Fail; + } + } + + using (TestTable<long> longTable = new TestTable<long>(new long[4] { 1, -5, 100, 0}, new long[4])) + { + var vf = Avx2.BroadcastVector128ToVector256((long*)(longTable.inArrayPtr)); + Unsafe.Write(longTable.outArrayPtr, vf); + + if (!longTable.CheckResult((x, y) => x == y)) + { + Console.WriteLine("Avx2 BroadcastVector128ToVector256 failed on long:"); + foreach (var item in longTable.outArray) + { + Console.Write(item + ", "); + } + Console.WriteLine(); + testResult = Fail; + } + } + + using (TestTable<ulong> ulongTable = new TestTable<ulong>(new ulong[4] { 1, 5, 100, 0}, new ulong[4])) + { + var vf = Avx2.BroadcastVector128ToVector256((ulong*)(ulongTable.inArrayPtr)); + Unsafe.Write(ulongTable.outArrayPtr, vf); + + if (!ulongTable.CheckResult((x, y) => x == y)) + { + Console.WriteLine("Avx2 BroadcastVector128ToVector256 failed on ulong:"); + foreach (var item in ulongTable.outArray) + { + Console.Write(item + ", "); + } + Console.WriteLine(); + testResult = Fail; + } + } + } + return testResult; + } + + public unsafe struct TestTable<T> : IDisposable where T : struct + { + public T[] inArray; + public T[] outArray; + + public void* inArrayPtr => inHandle.AddrOfPinnedObject().ToPointer(); + public void* outArrayPtr => outHandle.AddrOfPinnedObject().ToPointer(); + + GCHandle inHandle; + GCHandle outHandle; + public TestTable(T[] a, T[] b) + { + this.inArray = a; + this.outArray = b; + + inHandle = GCHandle.Alloc(inArray, GCHandleType.Pinned); + outHandle = GCHandle.Alloc(outArray, GCHandleType.Pinned); + } + public bool CheckResult(Func<T, T, bool> check) + { + for (int i = 0; i < outArray.Length/2; i++) + { + if (!check(inArray[i], outArray[i])) + { + return false; + } + } + for (int i = outArray.Length/2; i < outArray.Length; i++) + { + if (!check(inArray[i - outArray.Length/2], outArray[i])) + { + return false; + } + } + return true; + } + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + } + + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx2/BroadcastVector128ToVector256_r.csproj b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/BroadcastVector128ToVector256_r.csproj new file mode 100644 index 0000000000..1f4bcd4e36 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/BroadcastVector128ToVector256_r.csproj @@ -0,0 +1,34 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" /> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> + <SchemaVersion>2.0</SchemaVersion> + <ProjectGuid>{95DFC527-4DC1-495E-97D7-E94EE1F7140D}</ProjectGuid> + <OutputType>Exe</OutputType> + <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> + <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir> + <AllowUnsafeBlocks>true</AllowUnsafeBlocks> + </PropertyGroup> + <!-- Default configurations to help VS understand the configurations --> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "></PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' " /> + <ItemGroup> + <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies"> + <Visible>False</Visible> + </CodeAnalysisDependentAssemblyPaths> + </ItemGroup> + <PropertyGroup> + <DebugType>None</DebugType> + <Optimize></Optimize> + </PropertyGroup> + <ItemGroup> + <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" /> + </ItemGroup> + <ItemGroup> + <Compile Include="BroadcastVector128ToVector256.cs" /> + </ItemGroup> + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" /> + <PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' "></PropertyGroup> +</Project>
\ No newline at end of file diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx2/BroadcastVector128ToVector256_ro.csproj b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/BroadcastVector128ToVector256_ro.csproj new file mode 100644 index 0000000000..feecc1c334 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/BroadcastVector128ToVector256_ro.csproj @@ -0,0 +1,34 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" /> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> + <SchemaVersion>2.0</SchemaVersion> + <ProjectGuid>{95DFC527-4DC1-495E-97D7-E94EE1F7140D}</ProjectGuid> + <OutputType>Exe</OutputType> + <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> + <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir> + <AllowUnsafeBlocks>true</AllowUnsafeBlocks> + </PropertyGroup> + <!-- Default configurations to help VS understand the configurations --> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "></PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' " /> + <ItemGroup> + <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies"> + <Visible>False</Visible> + </CodeAnalysisDependentAssemblyPaths> + </ItemGroup> + <PropertyGroup> + <DebugType>None</DebugType> + <Optimize>True</Optimize> + </PropertyGroup> + <ItemGroup> + <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" /> + </ItemGroup> + <ItemGroup> + <Compile Include="BroadcastVector128ToVector256.cs" /> + </ItemGroup> + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" /> + <PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' "></PropertyGroup> +</Project>
\ No newline at end of file diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx2/ConvertToVector256Int16.SByte.cs b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/ConvertToVector256Int16.SByte.cs new file mode 100644 index 0000000000..92b47e7eba --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/ConvertToVector256Int16.SByte.cs @@ -0,0 +1,306 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\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.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.X86; + +namespace JIT.HardwareIntrinsics.X86 +{ + public static partial class Program + { + private static void ConvertToVector256Int16SByte() + { + var test = new SimpleUnaryOpTest__ConvertToVector256Int16SByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + + // Validates basic functionality works, using LoadAligned + test.RunBasicScenario_LoadAligned(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + + // Validates calling via reflection works, using LoadAligned + test.RunReflectionScenario_LoadAligned(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + + // Validates passing a local works, using LoadAligned + test.RunLclVarScenario_LoadAligned(); + } + + // Validates passing the field of a local works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + 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 SimpleUnaryOpTest__ConvertToVector256Int16SByte + { + private const int VectorSize = 32; + + private const int Op1ElementCount = 16 / sizeof(SByte); + private const int RetElementCount = VectorSize / sizeof(Int16); + + private static SByte[] _data = new SByte[Op1ElementCount]; + + private static Vector128<SByte> _clsVar; + + private Vector128<SByte> _fld; + + private SimpleUnaryOpTest__DataTable<Int16, SByte> _dataTable; + + static SimpleUnaryOpTest__ConvertToVector256Int16SByte() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<SByte>, byte>(ref _clsVar), ref Unsafe.As<SByte, byte>(ref _data[0]), 16); + } + + public SimpleUnaryOpTest__ConvertToVector256Int16SByte() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<SByte>, byte>(ref _fld), ref Unsafe.As<SByte, byte>(ref _data[0]), 16); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue)); } + _dataTable = new SimpleUnaryOpTest__DataTable<Int16, SByte>(_data, new Int16[RetElementCount], VectorSize); + } + + public bool IsSupported => Avx2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Avx2.ConvertToVector256Int16( + Unsafe.Read<Vector128<SByte>>(_dataTable.inArrayPtr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Avx2.ConvertToVector256Int16( + Sse2.LoadVector128((SByte*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Avx2.ConvertToVector256Int16( + Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.ConvertToVector256Int16), new Type[] { typeof(Vector128<SByte>) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector128<SByte>>(_dataTable.inArrayPtr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<Int16>)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.ConvertToVector256Int16), new Type[] { typeof(Vector128<SByte>) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((SByte*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<Int16>)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.ConvertToVector256Int16), new Type[] { typeof(Vector128<SByte>) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<Int16>)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Avx2.ConvertToVector256Int16( + _clsVar + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var firstOp = Unsafe.Read<Vector128<SByte>>(_dataTable.inArrayPtr); + var result = Avx2.ConvertToVector256Int16(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var firstOp = Sse2.LoadVector128((SByte*)(_dataTable.inArrayPtr)); + var result = Avx2.ConvertToVector256Int16(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var firstOp = Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArrayPtr)); + var result = Avx2.ConvertToVector256Int16(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleUnaryOpTest__ConvertToVector256Int16SByte(); + var result = Avx2.ConvertToVector256Int16(test._fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Avx2.ConvertToVector256Int16(_fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128<SByte> firstOp, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray = new SByte[Op1ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As<SByte, byte>(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int16, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray = new SByte[Op1ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<SByte, byte>(ref inArray[0]), ref Unsafe.AsRef<byte>(firstOp), 16); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int16, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(SByte[] firstOp, Int16[] result, [CallerMemberName] string method = "") + { + if (result[0] != firstOp[0]) + { + Succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != firstOp[i]) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Avx2)}.{nameof(Avx2.ConvertToVector256Int16)}<Int16>(Vector128<SByte>): {method} failed:"); + Console.WriteLine($" firstOp: ({string.Join(", ", firstOp)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx2/ConvertToVector256Int32.Int16.cs b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/ConvertToVector256Int32.Int16.cs new file mode 100644 index 0000000000..a197da2439 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/ConvertToVector256Int32.Int16.cs @@ -0,0 +1,306 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\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.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.X86; + +namespace JIT.HardwareIntrinsics.X86 +{ + public static partial class Program + { + private static void ConvertToVector256Int32Int16() + { + var test = new SimpleUnaryOpTest__ConvertToVector256Int32Int16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + + // Validates basic functionality works, using LoadAligned + test.RunBasicScenario_LoadAligned(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + + // Validates calling via reflection works, using LoadAligned + test.RunReflectionScenario_LoadAligned(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + + // Validates passing a local works, using LoadAligned + test.RunLclVarScenario_LoadAligned(); + } + + // Validates passing the field of a local works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + 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 SimpleUnaryOpTest__ConvertToVector256Int32Int16 + { + private const int VectorSize = 32; + + private const int Op1ElementCount = 16 / sizeof(Int16); + private const int RetElementCount = VectorSize / sizeof(Int32); + + private static Int16[] _data = new Int16[Op1ElementCount]; + + private static Vector128<Int16> _clsVar; + + private Vector128<Int16> _fld; + + private SimpleUnaryOpTest__DataTable<Int32, Int16> _dataTable; + + static SimpleUnaryOpTest__ConvertToVector256Int32Int16() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (short)(random.Next(short.MinValue, short.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int16>, byte>(ref _clsVar), ref Unsafe.As<Int16, byte>(ref _data[0]), 16); + } + + public SimpleUnaryOpTest__ConvertToVector256Int32Int16() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (short)(random.Next(short.MinValue, short.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int16>, byte>(ref _fld), ref Unsafe.As<Int16, byte>(ref _data[0]), 16); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (short)(random.Next(short.MinValue, short.MaxValue)); } + _dataTable = new SimpleUnaryOpTest__DataTable<Int32, Int16>(_data, new Int32[RetElementCount], VectorSize); + } + + public bool IsSupported => Avx2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Avx2.ConvertToVector256Int32( + Unsafe.Read<Vector128<Int16>>(_dataTable.inArrayPtr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Avx2.ConvertToVector256Int32( + Sse2.LoadVector128((Int16*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Avx2.ConvertToVector256Int32( + Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.ConvertToVector256Int32), new Type[] { typeof(Vector128<Int16>) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector128<Int16>>(_dataTable.inArrayPtr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<Int32>)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.ConvertToVector256Int32), new Type[] { typeof(Vector128<Int16>) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Int16*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<Int32>)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.ConvertToVector256Int32), new Type[] { typeof(Vector128<Int16>) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<Int32>)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Avx2.ConvertToVector256Int32( + _clsVar + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var firstOp = Unsafe.Read<Vector128<Int16>>(_dataTable.inArrayPtr); + var result = Avx2.ConvertToVector256Int32(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var firstOp = Sse2.LoadVector128((Int16*)(_dataTable.inArrayPtr)); + var result = Avx2.ConvertToVector256Int32(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var firstOp = Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArrayPtr)); + var result = Avx2.ConvertToVector256Int32(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleUnaryOpTest__ConvertToVector256Int32Int16(); + var result = Avx2.ConvertToVector256Int32(test._fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Avx2.ConvertToVector256Int32(_fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128<Int16> firstOp, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray = new Int16[Op1ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As<Int16, byte>(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int32, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray = new Int16[Op1ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int16, byte>(ref inArray[0]), ref Unsafe.AsRef<byte>(firstOp), 16); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int32, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Int16[] firstOp, Int32[] result, [CallerMemberName] string method = "") + { + if (result[0] != firstOp[0]) + { + Succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != firstOp[i]) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Avx2)}.{nameof(Avx2.ConvertToVector256Int32)}<Int32>(Vector128<Int16>): {method} failed:"); + Console.WriteLine($" firstOp: ({string.Join(", ", firstOp)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx2/ConvertToVector256Int32.SByte.cs b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/ConvertToVector256Int32.SByte.cs new file mode 100644 index 0000000000..47af229606 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/ConvertToVector256Int32.SByte.cs @@ -0,0 +1,306 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\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.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.X86; + +namespace JIT.HardwareIntrinsics.X86 +{ + public static partial class Program + { + private static void ConvertToVector256Int32SByte() + { + var test = new SimpleUnaryOpTest__ConvertToVector256Int32SByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + + // Validates basic functionality works, using LoadAligned + test.RunBasicScenario_LoadAligned(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + + // Validates calling via reflection works, using LoadAligned + test.RunReflectionScenario_LoadAligned(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + + // Validates passing a local works, using LoadAligned + test.RunLclVarScenario_LoadAligned(); + } + + // Validates passing the field of a local works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + 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 SimpleUnaryOpTest__ConvertToVector256Int32SByte + { + private const int VectorSize = 32; + + private const int Op1ElementCount = 16 / sizeof(SByte); + private const int RetElementCount = VectorSize / sizeof(Int32); + + private static SByte[] _data = new SByte[Op1ElementCount]; + + private static Vector128<SByte> _clsVar; + + private Vector128<SByte> _fld; + + private SimpleUnaryOpTest__DataTable<Int32, SByte> _dataTable; + + static SimpleUnaryOpTest__ConvertToVector256Int32SByte() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<SByte>, byte>(ref _clsVar), ref Unsafe.As<SByte, byte>(ref _data[0]), 16); + } + + public SimpleUnaryOpTest__ConvertToVector256Int32SByte() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<SByte>, byte>(ref _fld), ref Unsafe.As<SByte, byte>(ref _data[0]), 16); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue)); } + _dataTable = new SimpleUnaryOpTest__DataTable<Int32, SByte>(_data, new Int32[RetElementCount], VectorSize); + } + + public bool IsSupported => Avx2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Avx2.ConvertToVector256Int32( + Unsafe.Read<Vector128<SByte>>(_dataTable.inArrayPtr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Avx2.ConvertToVector256Int32( + Sse2.LoadVector128((SByte*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Avx2.ConvertToVector256Int32( + Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.ConvertToVector256Int32), new Type[] { typeof(Vector128<SByte>) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector128<SByte>>(_dataTable.inArrayPtr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<Int32>)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.ConvertToVector256Int32), new Type[] { typeof(Vector128<SByte>) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((SByte*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<Int32>)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.ConvertToVector256Int32), new Type[] { typeof(Vector128<SByte>) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<Int32>)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Avx2.ConvertToVector256Int32( + _clsVar + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var firstOp = Unsafe.Read<Vector128<SByte>>(_dataTable.inArrayPtr); + var result = Avx2.ConvertToVector256Int32(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var firstOp = Sse2.LoadVector128((SByte*)(_dataTable.inArrayPtr)); + var result = Avx2.ConvertToVector256Int32(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var firstOp = Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArrayPtr)); + var result = Avx2.ConvertToVector256Int32(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleUnaryOpTest__ConvertToVector256Int32SByte(); + var result = Avx2.ConvertToVector256Int32(test._fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Avx2.ConvertToVector256Int32(_fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128<SByte> firstOp, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray = new SByte[Op1ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As<SByte, byte>(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int32, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray = new SByte[Op1ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<SByte, byte>(ref inArray[0]), ref Unsafe.AsRef<byte>(firstOp), 16); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int32, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(SByte[] firstOp, Int32[] result, [CallerMemberName] string method = "") + { + if (result[0] != firstOp[0]) + { + Succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != firstOp[i]) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Avx2)}.{nameof(Avx2.ConvertToVector256Int32)}<Int32>(Vector128<SByte>): {method} failed:"); + Console.WriteLine($" firstOp: ({string.Join(", ", firstOp)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx2/ConvertToVector256Int64.Int16.cs b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/ConvertToVector256Int64.Int16.cs new file mode 100644 index 0000000000..092610d61d --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/ConvertToVector256Int64.Int16.cs @@ -0,0 +1,306 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\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.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.X86; + +namespace JIT.HardwareIntrinsics.X86 +{ + public static partial class Program + { + private static void ConvertToVector256Int64Int16() + { + var test = new SimpleUnaryOpTest__ConvertToVector256Int64Int16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + + // Validates basic functionality works, using LoadAligned + test.RunBasicScenario_LoadAligned(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + + // Validates calling via reflection works, using LoadAligned + test.RunReflectionScenario_LoadAligned(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + + // Validates passing a local works, using LoadAligned + test.RunLclVarScenario_LoadAligned(); + } + + // Validates passing the field of a local works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + 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 SimpleUnaryOpTest__ConvertToVector256Int64Int16 + { + private const int VectorSize = 32; + + private const int Op1ElementCount = 16 / sizeof(Int16); + private const int RetElementCount = VectorSize / sizeof(Int64); + + private static Int16[] _data = new Int16[Op1ElementCount]; + + private static Vector128<Int16> _clsVar; + + private Vector128<Int16> _fld; + + private SimpleUnaryOpTest__DataTable<Int64, Int16> _dataTable; + + static SimpleUnaryOpTest__ConvertToVector256Int64Int16() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (short)(random.Next(short.MinValue, short.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int16>, byte>(ref _clsVar), ref Unsafe.As<Int16, byte>(ref _data[0]), 16); + } + + public SimpleUnaryOpTest__ConvertToVector256Int64Int16() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (short)(random.Next(short.MinValue, short.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int16>, byte>(ref _fld), ref Unsafe.As<Int16, byte>(ref _data[0]), 16); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (short)(random.Next(short.MinValue, short.MaxValue)); } + _dataTable = new SimpleUnaryOpTest__DataTable<Int64, Int16>(_data, new Int64[RetElementCount], VectorSize); + } + + public bool IsSupported => Avx2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Avx2.ConvertToVector256Int64( + Unsafe.Read<Vector128<Int16>>(_dataTable.inArrayPtr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Avx2.ConvertToVector256Int64( + Sse2.LoadVector128((Int16*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Avx2.ConvertToVector256Int64( + Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.ConvertToVector256Int64), new Type[] { typeof(Vector128<Int16>) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector128<Int16>>(_dataTable.inArrayPtr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<Int64>)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.ConvertToVector256Int64), new Type[] { typeof(Vector128<Int16>) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Int16*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<Int64>)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.ConvertToVector256Int64), new Type[] { typeof(Vector128<Int16>) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<Int64>)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Avx2.ConvertToVector256Int64( + _clsVar + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var firstOp = Unsafe.Read<Vector128<Int16>>(_dataTable.inArrayPtr); + var result = Avx2.ConvertToVector256Int64(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var firstOp = Sse2.LoadVector128((Int16*)(_dataTable.inArrayPtr)); + var result = Avx2.ConvertToVector256Int64(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var firstOp = Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArrayPtr)); + var result = Avx2.ConvertToVector256Int64(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleUnaryOpTest__ConvertToVector256Int64Int16(); + var result = Avx2.ConvertToVector256Int64(test._fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Avx2.ConvertToVector256Int64(_fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128<Int16> firstOp, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray = new Int16[Op1ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As<Int16, byte>(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int64, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray = new Int16[Op1ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int16, byte>(ref inArray[0]), ref Unsafe.AsRef<byte>(firstOp), 16); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int64, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Int16[] firstOp, Int64[] result, [CallerMemberName] string method = "") + { + if (result[0] != firstOp[0]) + { + Succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != firstOp[i]) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Avx2)}.{nameof(Avx2.ConvertToVector256Int64)}<Int64>(Vector128<Int16>): {method} failed:"); + Console.WriteLine($" firstOp: ({string.Join(", ", firstOp)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx2/ConvertToVector256Int64.Int32.cs b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/ConvertToVector256Int64.Int32.cs new file mode 100644 index 0000000000..f1c16ee090 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/ConvertToVector256Int64.Int32.cs @@ -0,0 +1,306 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\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.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.X86; + +namespace JIT.HardwareIntrinsics.X86 +{ + public static partial class Program + { + private static void ConvertToVector256Int64Int32() + { + var test = new SimpleUnaryOpTest__ConvertToVector256Int64Int32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + + // Validates basic functionality works, using LoadAligned + test.RunBasicScenario_LoadAligned(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + + // Validates calling via reflection works, using LoadAligned + test.RunReflectionScenario_LoadAligned(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + + // Validates passing a local works, using LoadAligned + test.RunLclVarScenario_LoadAligned(); + } + + // Validates passing the field of a local works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + 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 SimpleUnaryOpTest__ConvertToVector256Int64Int32 + { + private const int VectorSize = 32; + + private const int Op1ElementCount = 16 / sizeof(Int32); + private const int RetElementCount = VectorSize / sizeof(Int64); + + private static Int32[] _data = new Int32[Op1ElementCount]; + + private static Vector128<Int32> _clsVar; + + private Vector128<Int32> _fld; + + private SimpleUnaryOpTest__DataTable<Int64, Int32> _dataTable; + + static SimpleUnaryOpTest__ConvertToVector256Int64Int32() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (int)(random.Next(int.MinValue, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int32>, byte>(ref _clsVar), ref Unsafe.As<Int32, byte>(ref _data[0]), 16); + } + + public SimpleUnaryOpTest__ConvertToVector256Int64Int32() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (int)(random.Next(int.MinValue, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int32>, byte>(ref _fld), ref Unsafe.As<Int32, byte>(ref _data[0]), 16); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (int)(random.Next(int.MinValue, int.MaxValue)); } + _dataTable = new SimpleUnaryOpTest__DataTable<Int64, Int32>(_data, new Int64[RetElementCount], VectorSize); + } + + public bool IsSupported => Avx2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Avx2.ConvertToVector256Int64( + Unsafe.Read<Vector128<Int32>>(_dataTable.inArrayPtr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Avx2.ConvertToVector256Int64( + Sse2.LoadVector128((Int32*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Avx2.ConvertToVector256Int64( + Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.ConvertToVector256Int64), new Type[] { typeof(Vector128<Int32>) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector128<Int32>>(_dataTable.inArrayPtr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<Int64>)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.ConvertToVector256Int64), new Type[] { typeof(Vector128<Int32>) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Int32*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<Int64>)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.ConvertToVector256Int64), new Type[] { typeof(Vector128<Int32>) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<Int64>)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Avx2.ConvertToVector256Int64( + _clsVar + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var firstOp = Unsafe.Read<Vector128<Int32>>(_dataTable.inArrayPtr); + var result = Avx2.ConvertToVector256Int64(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var firstOp = Sse2.LoadVector128((Int32*)(_dataTable.inArrayPtr)); + var result = Avx2.ConvertToVector256Int64(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var firstOp = Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArrayPtr)); + var result = Avx2.ConvertToVector256Int64(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleUnaryOpTest__ConvertToVector256Int64Int32(); + var result = Avx2.ConvertToVector256Int64(test._fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Avx2.ConvertToVector256Int64(_fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128<Int32> firstOp, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray = new Int32[Op1ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As<Int32, byte>(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int64, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray = new Int32[Op1ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int32, byte>(ref inArray[0]), ref Unsafe.AsRef<byte>(firstOp), 16); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int64, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Int32[] firstOp, Int64[] result, [CallerMemberName] string method = "") + { + if (result[0] != firstOp[0]) + { + Succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != firstOp[i]) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Avx2)}.{nameof(Avx2.ConvertToVector256Int64)}<Int64>(Vector128<Int32>): {method} failed:"); + Console.WriteLine($" firstOp: ({string.Join(", ", firstOp)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx2/ConvertToVector256Int64.SByte.cs b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/ConvertToVector256Int64.SByte.cs new file mode 100644 index 0000000000..f3848d55e6 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/ConvertToVector256Int64.SByte.cs @@ -0,0 +1,306 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\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.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.X86; + +namespace JIT.HardwareIntrinsics.X86 +{ + public static partial class Program + { + private static void ConvertToVector256Int64SByte() + { + var test = new SimpleUnaryOpTest__ConvertToVector256Int64SByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + + // Validates basic functionality works, using LoadAligned + test.RunBasicScenario_LoadAligned(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + + // Validates calling via reflection works, using LoadAligned + test.RunReflectionScenario_LoadAligned(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + + // Validates passing a local works, using LoadAligned + test.RunLclVarScenario_LoadAligned(); + } + + // Validates passing the field of a local works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + 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 SimpleUnaryOpTest__ConvertToVector256Int64SByte + { + private const int VectorSize = 32; + + private const int Op1ElementCount = 16 / sizeof(SByte); + private const int RetElementCount = VectorSize / sizeof(Int64); + + private static SByte[] _data = new SByte[Op1ElementCount]; + + private static Vector128<SByte> _clsVar; + + private Vector128<SByte> _fld; + + private SimpleUnaryOpTest__DataTable<Int64, SByte> _dataTable; + + static SimpleUnaryOpTest__ConvertToVector256Int64SByte() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<SByte>, byte>(ref _clsVar), ref Unsafe.As<SByte, byte>(ref _data[0]), 16); + } + + public SimpleUnaryOpTest__ConvertToVector256Int64SByte() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<SByte>, byte>(ref _fld), ref Unsafe.As<SByte, byte>(ref _data[0]), 16); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue)); } + _dataTable = new SimpleUnaryOpTest__DataTable<Int64, SByte>(_data, new Int64[RetElementCount], VectorSize); + } + + public bool IsSupported => Avx2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Avx2.ConvertToVector256Int64( + Unsafe.Read<Vector128<SByte>>(_dataTable.inArrayPtr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Avx2.ConvertToVector256Int64( + Sse2.LoadVector128((SByte*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Avx2.ConvertToVector256Int64( + Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.ConvertToVector256Int64), new Type[] { typeof(Vector128<SByte>) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector128<SByte>>(_dataTable.inArrayPtr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<Int64>)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.ConvertToVector256Int64), new Type[] { typeof(Vector128<SByte>) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((SByte*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<Int64>)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.ConvertToVector256Int64), new Type[] { typeof(Vector128<SByte>) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<Int64>)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Avx2.ConvertToVector256Int64( + _clsVar + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var firstOp = Unsafe.Read<Vector128<SByte>>(_dataTable.inArrayPtr); + var result = Avx2.ConvertToVector256Int64(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var firstOp = Sse2.LoadVector128((SByte*)(_dataTable.inArrayPtr)); + var result = Avx2.ConvertToVector256Int64(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var firstOp = Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArrayPtr)); + var result = Avx2.ConvertToVector256Int64(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleUnaryOpTest__ConvertToVector256Int64SByte(); + var result = Avx2.ConvertToVector256Int64(test._fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Avx2.ConvertToVector256Int64(_fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128<SByte> firstOp, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray = new SByte[Op1ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As<SByte, byte>(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int64, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray = new SByte[Op1ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<SByte, byte>(ref inArray[0]), ref Unsafe.AsRef<byte>(firstOp), 16); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int64, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(SByte[] firstOp, Int64[] result, [CallerMemberName] string method = "") + { + if (result[0] != firstOp[0]) + { + Succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != firstOp[i]) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Avx2)}.{nameof(Avx2.ConvertToVector256Int64)}<Int64>(Vector128<SByte>): {method} failed:"); + Console.WriteLine($" firstOp: ({string.Join(", ", firstOp)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx2/ConvertToVector256UInt16.Byte.cs b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/ConvertToVector256UInt16.Byte.cs new file mode 100644 index 0000000000..682b76a894 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/ConvertToVector256UInt16.Byte.cs @@ -0,0 +1,306 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\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.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.X86; + +namespace JIT.HardwareIntrinsics.X86 +{ + public static partial class Program + { + private static void ConvertToVector256UInt16Byte() + { + var test = new SimpleUnaryOpTest__ConvertToVector256UInt16Byte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + + // Validates basic functionality works, using LoadAligned + test.RunBasicScenario_LoadAligned(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + + // Validates calling via reflection works, using LoadAligned + test.RunReflectionScenario_LoadAligned(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + + // Validates passing a local works, using LoadAligned + test.RunLclVarScenario_LoadAligned(); + } + + // Validates passing the field of a local works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + 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 SimpleUnaryOpTest__ConvertToVector256UInt16Byte + { + private const int VectorSize = 32; + + private const int Op1ElementCount = 16 / sizeof(Byte); + private const int RetElementCount = VectorSize / sizeof(Int16); + + private static Byte[] _data = new Byte[Op1ElementCount]; + + private static Vector128<Byte> _clsVar; + + private Vector128<Byte> _fld; + + private SimpleUnaryOpTest__DataTable<UInt16, Byte> _dataTable; + + static SimpleUnaryOpTest__ConvertToVector256UInt16Byte() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (byte)(random.Next(0, byte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Byte>, byte>(ref _clsVar), ref Unsafe.As<Byte, byte>(ref _data[0]), 16); + } + + public SimpleUnaryOpTest__ConvertToVector256UInt16Byte() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (byte)(random.Next(0, byte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Byte>, byte>(ref _fld), ref Unsafe.As<Byte, byte>(ref _data[0]), 16); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (byte)(random.Next(0, byte.MaxValue)); } + _dataTable = new SimpleUnaryOpTest__DataTable<UInt16, Byte>(_data, new UInt16[RetElementCount], VectorSize); + } + + public bool IsSupported => Avx2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Avx2.ConvertToVector256UInt16( + Unsafe.Read<Vector128<Byte>>(_dataTable.inArrayPtr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Avx2.ConvertToVector256UInt16( + Sse2.LoadVector128((Byte*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Avx2.ConvertToVector256UInt16( + Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.ConvertToVector256UInt16), new Type[] { typeof(Vector128<Byte>) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector128<Byte>>(_dataTable.inArrayPtr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<UInt16>)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.ConvertToVector256UInt16), new Type[] { typeof(Vector128<Byte>) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Byte*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<UInt16>)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.ConvertToVector256UInt16), new Type[] { typeof(Vector128<Byte>) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<UInt16>)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Avx2.ConvertToVector256UInt16( + _clsVar + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var firstOp = Unsafe.Read<Vector128<Byte>>(_dataTable.inArrayPtr); + var result = Avx2.ConvertToVector256UInt16(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var firstOp = Sse2.LoadVector128((Byte*)(_dataTable.inArrayPtr)); + var result = Avx2.ConvertToVector256UInt16(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var firstOp = Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArrayPtr)); + var result = Avx2.ConvertToVector256UInt16(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleUnaryOpTest__ConvertToVector256UInt16Byte(); + var result = Avx2.ConvertToVector256UInt16(test._fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Avx2.ConvertToVector256UInt16(_fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128<Byte> firstOp, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray = new Byte[Op1ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As<Byte, byte>(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt16, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray = new Byte[Op1ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Byte, byte>(ref inArray[0]), ref Unsafe.AsRef<byte>(firstOp), 16); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt16, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Byte[] firstOp, UInt16[] result, [CallerMemberName] string method = "") + { + if (result[0] != firstOp[0]) + { + Succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != firstOp[i]) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Avx2)}.{nameof(Avx2.ConvertToVector256UInt16)}<UInt16>(Vector128<Byte>): {method} failed:"); + Console.WriteLine($" firstOp: ({string.Join(", ", firstOp)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx2/ConvertToVector256UInt32.Byte.cs b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/ConvertToVector256UInt32.Byte.cs new file mode 100644 index 0000000000..89202c2f1e --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/ConvertToVector256UInt32.Byte.cs @@ -0,0 +1,306 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\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.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.X86; + +namespace JIT.HardwareIntrinsics.X86 +{ + public static partial class Program + { + private static void ConvertToVector256UInt32Byte() + { + var test = new SimpleUnaryOpTest__ConvertToVector256UInt32Byte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + + // Validates basic functionality works, using LoadAligned + test.RunBasicScenario_LoadAligned(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + + // Validates calling via reflection works, using LoadAligned + test.RunReflectionScenario_LoadAligned(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + + // Validates passing a local works, using LoadAligned + test.RunLclVarScenario_LoadAligned(); + } + + // Validates passing the field of a local works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + 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 SimpleUnaryOpTest__ConvertToVector256UInt32Byte + { + private const int VectorSize = 32; + + private const int Op1ElementCount = 16 / sizeof(Byte); + private const int RetElementCount = VectorSize / sizeof(Int32); + + private static Byte[] _data = new Byte[Op1ElementCount]; + + private static Vector128<Byte> _clsVar; + + private Vector128<Byte> _fld; + + private SimpleUnaryOpTest__DataTable<UInt32, Byte> _dataTable; + + static SimpleUnaryOpTest__ConvertToVector256UInt32Byte() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (byte)(random.Next(0, byte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Byte>, byte>(ref _clsVar), ref Unsafe.As<Byte, byte>(ref _data[0]), 16); + } + + public SimpleUnaryOpTest__ConvertToVector256UInt32Byte() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (byte)(random.Next(0, byte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Byte>, byte>(ref _fld), ref Unsafe.As<Byte, byte>(ref _data[0]), 16); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (byte)(random.Next(0, byte.MaxValue)); } + _dataTable = new SimpleUnaryOpTest__DataTable<UInt32, Byte>(_data, new UInt32[RetElementCount], VectorSize); + } + + public bool IsSupported => Avx2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Avx2.ConvertToVector256UInt32( + Unsafe.Read<Vector128<Byte>>(_dataTable.inArrayPtr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Avx2.ConvertToVector256UInt32( + Sse2.LoadVector128((Byte*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Avx2.ConvertToVector256UInt32( + Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.ConvertToVector256UInt32), new Type[] { typeof(Vector128<Byte>) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector128<Byte>>(_dataTable.inArrayPtr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<UInt32>)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.ConvertToVector256UInt32), new Type[] { typeof(Vector128<Byte>) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Byte*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<UInt32>)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.ConvertToVector256UInt32), new Type[] { typeof(Vector128<Byte>) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<UInt32>)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Avx2.ConvertToVector256UInt32( + _clsVar + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var firstOp = Unsafe.Read<Vector128<Byte>>(_dataTable.inArrayPtr); + var result = Avx2.ConvertToVector256UInt32(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var firstOp = Sse2.LoadVector128((Byte*)(_dataTable.inArrayPtr)); + var result = Avx2.ConvertToVector256UInt32(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var firstOp = Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArrayPtr)); + var result = Avx2.ConvertToVector256UInt32(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleUnaryOpTest__ConvertToVector256UInt32Byte(); + var result = Avx2.ConvertToVector256UInt32(test._fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Avx2.ConvertToVector256UInt32(_fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128<Byte> firstOp, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray = new Byte[Op1ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As<Byte, byte>(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt32, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray = new Byte[Op1ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Byte, byte>(ref inArray[0]), ref Unsafe.AsRef<byte>(firstOp), 16); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt32, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Byte[] firstOp, UInt32[] result, [CallerMemberName] string method = "") + { + if (result[0] != firstOp[0]) + { + Succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != firstOp[i]) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Avx2)}.{nameof(Avx2.ConvertToVector256UInt32)}<UInt32>(Vector128<Byte>): {method} failed:"); + Console.WriteLine($" firstOp: ({string.Join(", ", firstOp)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx2/ConvertToVector256UInt32.UInt16.cs b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/ConvertToVector256UInt32.UInt16.cs new file mode 100644 index 0000000000..afb35c6404 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/ConvertToVector256UInt32.UInt16.cs @@ -0,0 +1,306 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\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.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.X86; + +namespace JIT.HardwareIntrinsics.X86 +{ + public static partial class Program + { + private static void ConvertToVector256UInt32UInt16() + { + var test = new SimpleUnaryOpTest__ConvertToVector256UInt32UInt16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + + // Validates basic functionality works, using LoadAligned + test.RunBasicScenario_LoadAligned(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + + // Validates calling via reflection works, using LoadAligned + test.RunReflectionScenario_LoadAligned(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + + // Validates passing a local works, using LoadAligned + test.RunLclVarScenario_LoadAligned(); + } + + // Validates passing the field of a local works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + 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 SimpleUnaryOpTest__ConvertToVector256UInt32UInt16 + { + private const int VectorSize = 32; + + private const int Op1ElementCount = 16 / sizeof(UInt16); + private const int RetElementCount = VectorSize / sizeof(Int32); + + private static UInt16[] _data = new UInt16[Op1ElementCount]; + + private static Vector128<UInt16> _clsVar; + + private Vector128<UInt16> _fld; + + private SimpleUnaryOpTest__DataTable<UInt32, UInt16> _dataTable; + + static SimpleUnaryOpTest__ConvertToVector256UInt32UInt16() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (ushort)(random.Next(0, ushort.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt16>, byte>(ref _clsVar), ref Unsafe.As<UInt16, byte>(ref _data[0]), 16); + } + + public SimpleUnaryOpTest__ConvertToVector256UInt32UInt16() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (ushort)(random.Next(0, ushort.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt16>, byte>(ref _fld), ref Unsafe.As<UInt16, byte>(ref _data[0]), 16); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (ushort)(random.Next(0, ushort.MaxValue)); } + _dataTable = new SimpleUnaryOpTest__DataTable<UInt32, UInt16>(_data, new UInt32[RetElementCount], VectorSize); + } + + public bool IsSupported => Avx2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Avx2.ConvertToVector256UInt32( + Unsafe.Read<Vector128<UInt16>>(_dataTable.inArrayPtr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Avx2.ConvertToVector256UInt32( + Sse2.LoadVector128((UInt16*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Avx2.ConvertToVector256UInt32( + Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.ConvertToVector256UInt32), new Type[] { typeof(Vector128<UInt16>) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector128<UInt16>>(_dataTable.inArrayPtr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<UInt32>)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.ConvertToVector256UInt32), new Type[] { typeof(Vector128<UInt16>) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((UInt16*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<UInt32>)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.ConvertToVector256UInt32), new Type[] { typeof(Vector128<UInt16>) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<UInt32>)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Avx2.ConvertToVector256UInt32( + _clsVar + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var firstOp = Unsafe.Read<Vector128<UInt16>>(_dataTable.inArrayPtr); + var result = Avx2.ConvertToVector256UInt32(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var firstOp = Sse2.LoadVector128((UInt16*)(_dataTable.inArrayPtr)); + var result = Avx2.ConvertToVector256UInt32(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var firstOp = Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArrayPtr)); + var result = Avx2.ConvertToVector256UInt32(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleUnaryOpTest__ConvertToVector256UInt32UInt16(); + var result = Avx2.ConvertToVector256UInt32(test._fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Avx2.ConvertToVector256UInt32(_fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128<UInt16> firstOp, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray = new UInt16[Op1ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As<UInt16, byte>(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt32, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray = new UInt16[Op1ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt16, byte>(ref inArray[0]), ref Unsafe.AsRef<byte>(firstOp), 16); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt32, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(UInt16[] firstOp, UInt32[] result, [CallerMemberName] string method = "") + { + if (result[0] != firstOp[0]) + { + Succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != firstOp[i]) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Avx2)}.{nameof(Avx2.ConvertToVector256UInt32)}<UInt32>(Vector128<UInt16>): {method} failed:"); + Console.WriteLine($" firstOp: ({string.Join(", ", firstOp)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx2/ConvertToVector256UInt64.Byte.cs b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/ConvertToVector256UInt64.Byte.cs new file mode 100644 index 0000000000..4d95740aaa --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/ConvertToVector256UInt64.Byte.cs @@ -0,0 +1,306 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\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.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.X86; + +namespace JIT.HardwareIntrinsics.X86 +{ + public static partial class Program + { + private static void ConvertToVector256UInt64Byte() + { + var test = new SimpleUnaryOpTest__ConvertToVector256UInt64Byte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + + // Validates basic functionality works, using LoadAligned + test.RunBasicScenario_LoadAligned(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + + // Validates calling via reflection works, using LoadAligned + test.RunReflectionScenario_LoadAligned(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + + // Validates passing a local works, using LoadAligned + test.RunLclVarScenario_LoadAligned(); + } + + // Validates passing the field of a local works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + 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 SimpleUnaryOpTest__ConvertToVector256UInt64Byte + { + private const int VectorSize = 32; + + private const int Op1ElementCount = 16 / sizeof(Byte); + private const int RetElementCount = VectorSize / sizeof(Int64); + + private static Byte[] _data = new Byte[Op1ElementCount]; + + private static Vector128<Byte> _clsVar; + + private Vector128<Byte> _fld; + + private SimpleUnaryOpTest__DataTable<UInt64, Byte> _dataTable; + + static SimpleUnaryOpTest__ConvertToVector256UInt64Byte() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (byte)(random.Next(0, byte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Byte>, byte>(ref _clsVar), ref Unsafe.As<Byte, byte>(ref _data[0]), 16); + } + + public SimpleUnaryOpTest__ConvertToVector256UInt64Byte() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (byte)(random.Next(0, byte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Byte>, byte>(ref _fld), ref Unsafe.As<Byte, byte>(ref _data[0]), 16); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (byte)(random.Next(0, byte.MaxValue)); } + _dataTable = new SimpleUnaryOpTest__DataTable<UInt64, Byte>(_data, new UInt64[RetElementCount], VectorSize); + } + + public bool IsSupported => Avx2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Avx2.ConvertToVector256UInt64( + Unsafe.Read<Vector128<Byte>>(_dataTable.inArrayPtr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Avx2.ConvertToVector256UInt64( + Sse2.LoadVector128((Byte*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Avx2.ConvertToVector256UInt64( + Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.ConvertToVector256UInt64), new Type[] { typeof(Vector128<Byte>) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector128<Byte>>(_dataTable.inArrayPtr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<UInt64>)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.ConvertToVector256UInt64), new Type[] { typeof(Vector128<Byte>) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Byte*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<UInt64>)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.ConvertToVector256UInt64), new Type[] { typeof(Vector128<Byte>) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<UInt64>)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Avx2.ConvertToVector256UInt64( + _clsVar + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var firstOp = Unsafe.Read<Vector128<Byte>>(_dataTable.inArrayPtr); + var result = Avx2.ConvertToVector256UInt64(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var firstOp = Sse2.LoadVector128((Byte*)(_dataTable.inArrayPtr)); + var result = Avx2.ConvertToVector256UInt64(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var firstOp = Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArrayPtr)); + var result = Avx2.ConvertToVector256UInt64(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleUnaryOpTest__ConvertToVector256UInt64Byte(); + var result = Avx2.ConvertToVector256UInt64(test._fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Avx2.ConvertToVector256UInt64(_fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128<Byte> firstOp, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray = new Byte[Op1ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As<Byte, byte>(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt64, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray = new Byte[Op1ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Byte, byte>(ref inArray[0]), ref Unsafe.AsRef<byte>(firstOp), 16); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt64, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Byte[] firstOp, UInt64[] result, [CallerMemberName] string method = "") + { + if (result[0] != firstOp[0]) + { + Succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != firstOp[i]) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Avx2)}.{nameof(Avx2.ConvertToVector256UInt64)}<UInt64>(Vector128<Byte>): {method} failed:"); + Console.WriteLine($" firstOp: ({string.Join(", ", firstOp)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx2/ConvertToVector256UInt64.UInt16.cs b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/ConvertToVector256UInt64.UInt16.cs new file mode 100644 index 0000000000..48d5d7f954 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/ConvertToVector256UInt64.UInt16.cs @@ -0,0 +1,306 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\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.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.X86; + +namespace JIT.HardwareIntrinsics.X86 +{ + public static partial class Program + { + private static void ConvertToVector256UInt64UInt16() + { + var test = new SimpleUnaryOpTest__ConvertToVector256UInt64UInt16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + + // Validates basic functionality works, using LoadAligned + test.RunBasicScenario_LoadAligned(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + + // Validates calling via reflection works, using LoadAligned + test.RunReflectionScenario_LoadAligned(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + + // Validates passing a local works, using LoadAligned + test.RunLclVarScenario_LoadAligned(); + } + + // Validates passing the field of a local works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + 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 SimpleUnaryOpTest__ConvertToVector256UInt64UInt16 + { + private const int VectorSize = 32; + + private const int Op1ElementCount = 16 / sizeof(UInt16); + private const int RetElementCount = VectorSize / sizeof(Int64); + + private static UInt16[] _data = new UInt16[Op1ElementCount]; + + private static Vector128<UInt16> _clsVar; + + private Vector128<UInt16> _fld; + + private SimpleUnaryOpTest__DataTable<UInt64, UInt16> _dataTable; + + static SimpleUnaryOpTest__ConvertToVector256UInt64UInt16() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (ushort)(random.Next(0, ushort.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt16>, byte>(ref _clsVar), ref Unsafe.As<UInt16, byte>(ref _data[0]), 16); + } + + public SimpleUnaryOpTest__ConvertToVector256UInt64UInt16() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (ushort)(random.Next(0, ushort.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt16>, byte>(ref _fld), ref Unsafe.As<UInt16, byte>(ref _data[0]), 16); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (ushort)(random.Next(0, ushort.MaxValue)); } + _dataTable = new SimpleUnaryOpTest__DataTable<UInt64, UInt16>(_data, new UInt64[RetElementCount], VectorSize); + } + + public bool IsSupported => Avx2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Avx2.ConvertToVector256UInt64( + Unsafe.Read<Vector128<UInt16>>(_dataTable.inArrayPtr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Avx2.ConvertToVector256UInt64( + Sse2.LoadVector128((UInt16*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Avx2.ConvertToVector256UInt64( + Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.ConvertToVector256UInt64), new Type[] { typeof(Vector128<UInt16>) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector128<UInt16>>(_dataTable.inArrayPtr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<UInt64>)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.ConvertToVector256UInt64), new Type[] { typeof(Vector128<UInt16>) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((UInt16*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<UInt64>)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.ConvertToVector256UInt64), new Type[] { typeof(Vector128<UInt16>) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<UInt64>)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Avx2.ConvertToVector256UInt64( + _clsVar + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var firstOp = Unsafe.Read<Vector128<UInt16>>(_dataTable.inArrayPtr); + var result = Avx2.ConvertToVector256UInt64(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var firstOp = Sse2.LoadVector128((UInt16*)(_dataTable.inArrayPtr)); + var result = Avx2.ConvertToVector256UInt64(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var firstOp = Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArrayPtr)); + var result = Avx2.ConvertToVector256UInt64(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleUnaryOpTest__ConvertToVector256UInt64UInt16(); + var result = Avx2.ConvertToVector256UInt64(test._fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Avx2.ConvertToVector256UInt64(_fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128<UInt16> firstOp, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray = new UInt16[Op1ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As<UInt16, byte>(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt64, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray = new UInt16[Op1ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt16, byte>(ref inArray[0]), ref Unsafe.AsRef<byte>(firstOp), 16); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt64, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(UInt16[] firstOp, UInt64[] result, [CallerMemberName] string method = "") + { + if (result[0] != firstOp[0]) + { + Succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != firstOp[i]) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Avx2)}.{nameof(Avx2.ConvertToVector256UInt64)}<UInt64>(Vector128<UInt16>): {method} failed:"); + Console.WriteLine($" firstOp: ({string.Join(", ", firstOp)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx2/ConvertToVector256UInt64.UInt32.cs b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/ConvertToVector256UInt64.UInt32.cs new file mode 100644 index 0000000000..67f361b4f1 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/ConvertToVector256UInt64.UInt32.cs @@ -0,0 +1,306 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\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.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.X86; + +namespace JIT.HardwareIntrinsics.X86 +{ + public static partial class Program + { + private static void ConvertToVector256UInt64UInt32() + { + var test = new SimpleUnaryOpTest__ConvertToVector256UInt64UInt32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + + // Validates basic functionality works, using LoadAligned + test.RunBasicScenario_LoadAligned(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + + // Validates calling via reflection works, using LoadAligned + test.RunReflectionScenario_LoadAligned(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + + // Validates passing a local works, using LoadAligned + test.RunLclVarScenario_LoadAligned(); + } + + // Validates passing the field of a local works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + 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 SimpleUnaryOpTest__ConvertToVector256UInt64UInt32 + { + private const int VectorSize = 32; + + private const int Op1ElementCount = 16 / sizeof(UInt32); + private const int RetElementCount = VectorSize / sizeof(Int64); + + private static UInt32[] _data = new UInt32[Op1ElementCount]; + + private static Vector128<UInt32> _clsVar; + + private Vector128<UInt32> _fld; + + private SimpleUnaryOpTest__DataTable<UInt64, UInt32> _dataTable; + + static SimpleUnaryOpTest__ConvertToVector256UInt64UInt32() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (uint)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt32>, byte>(ref _clsVar), ref Unsafe.As<UInt32, byte>(ref _data[0]), 16); + } + + public SimpleUnaryOpTest__ConvertToVector256UInt64UInt32() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (uint)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt32>, byte>(ref _fld), ref Unsafe.As<UInt32, byte>(ref _data[0]), 16); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (uint)(random.Next(0, int.MaxValue)); } + _dataTable = new SimpleUnaryOpTest__DataTable<UInt64, UInt32>(_data, new UInt64[RetElementCount], VectorSize); + } + + public bool IsSupported => Avx2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Avx2.ConvertToVector256UInt64( + Unsafe.Read<Vector128<UInt32>>(_dataTable.inArrayPtr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Avx2.ConvertToVector256UInt64( + Sse2.LoadVector128((UInt32*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Avx2.ConvertToVector256UInt64( + Sse2.LoadAlignedVector128((UInt32*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.ConvertToVector256UInt64), new Type[] { typeof(Vector128<UInt32>) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector128<UInt32>>(_dataTable.inArrayPtr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<UInt64>)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.ConvertToVector256UInt64), new Type[] { typeof(Vector128<UInt32>) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((UInt32*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<UInt64>)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.ConvertToVector256UInt64), new Type[] { typeof(Vector128<UInt32>) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((UInt32*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<UInt64>)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Avx2.ConvertToVector256UInt64( + _clsVar + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var firstOp = Unsafe.Read<Vector128<UInt32>>(_dataTable.inArrayPtr); + var result = Avx2.ConvertToVector256UInt64(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var firstOp = Sse2.LoadVector128((UInt32*)(_dataTable.inArrayPtr)); + var result = Avx2.ConvertToVector256UInt64(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var firstOp = Sse2.LoadAlignedVector128((UInt32*)(_dataTable.inArrayPtr)); + var result = Avx2.ConvertToVector256UInt64(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleUnaryOpTest__ConvertToVector256UInt64UInt32(); + var result = Avx2.ConvertToVector256UInt64(test._fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Avx2.ConvertToVector256UInt64(_fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128<UInt32> firstOp, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray = new UInt32[Op1ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As<UInt32, byte>(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt64, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray = new UInt32[Op1ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt32, byte>(ref inArray[0]), ref Unsafe.AsRef<byte>(firstOp), 16); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt64, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(UInt32[] firstOp, UInt64[] result, [CallerMemberName] string method = "") + { + if (result[0] != firstOp[0]) + { + Succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != firstOp[i]) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Avx2)}.{nameof(Avx2.ConvertToVector256UInt64)}<UInt64>(Vector128<UInt32>): {method} failed:"); + Console.WriteLine($" firstOp: ({string.Join(", ", firstOp)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx2/ConvertToVector256_r.csproj b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/ConvertToVector256_r.csproj new file mode 100644 index 0000000000..c240eab6b3 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/ConvertToVector256_r.csproj @@ -0,0 +1,48 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" /> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> + <SchemaVersion>2.0</SchemaVersion> + <ProjectGuid>{95DFC527-4DC1-495E-97D7-E94EE1F7140D}</ProjectGuid> + <OutputType>Exe</OutputType> + <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> + <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir> + <AllowUnsafeBlocks>true</AllowUnsafeBlocks> + </PropertyGroup> + <!-- Default configurations to help VS understand the configurations --> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "></PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' " /> + <ItemGroup> + <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies"> + <Visible>False</Visible> + </CodeAnalysisDependentAssemblyPaths> + </ItemGroup> + <PropertyGroup> + <DebugType>None</DebugType> + <Optimize></Optimize> + </PropertyGroup> + <ItemGroup> + <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" /> + </ItemGroup> + <ItemGroup> + <Compile Include="ConvertToVector256UInt16.Byte.cs" /> + <Compile Include="ConvertToVector256Int16.SByte.cs" /> + <Compile Include="ConvertToVector256UInt32.Byte.cs" /> + <Compile Include="ConvertToVector256Int32.Int16.cs" /> + <Compile Include="ConvertToVector256Int32.SByte.cs" /> + <Compile Include="ConvertToVector256UInt32.UInt16.cs" /> + <Compile Include="ConvertToVector256UInt64.Byte.cs" /> + <Compile Include="ConvertToVector256Int64.Int16.cs" /> + <Compile Include="ConvertToVector256Int64.Int32.cs" /> + <Compile Include="ConvertToVector256Int64.SByte.cs" /> + <Compile Include="ConvertToVector256UInt64.UInt16.cs" /> + <Compile Include="ConvertToVector256UInt64.UInt32.cs" /> + <Compile Include="Program.ConvertToVector256.cs" /> + <Compile Include="..\Shared\Program.cs" /> + <Compile Include="..\Shared\SimpleUnOpTest_DataTable.cs" /> + </ItemGroup> + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" /> + <PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' "></PropertyGroup> +</Project> diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx2/ConvertToVector256_ro.csproj b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/ConvertToVector256_ro.csproj new file mode 100644 index 0000000000..15b943a683 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/ConvertToVector256_ro.csproj @@ -0,0 +1,48 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" /> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> + <SchemaVersion>2.0</SchemaVersion> + <ProjectGuid>{95DFC527-4DC1-495E-97D7-E94EE1F7140D}</ProjectGuid> + <OutputType>Exe</OutputType> + <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> + <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir> + <AllowUnsafeBlocks>true</AllowUnsafeBlocks> + </PropertyGroup> + <!-- Default configurations to help VS understand the configurations --> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "></PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' " /> + <ItemGroup> + <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies"> + <Visible>False</Visible> + </CodeAnalysisDependentAssemblyPaths> + </ItemGroup> + <PropertyGroup> + <DebugType>None</DebugType> + <Optimize>True</Optimize> + </PropertyGroup> + <ItemGroup> + <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" /> + </ItemGroup> + <ItemGroup> + <Compile Include="ConvertToVector256UInt16.Byte.cs" /> + <Compile Include="ConvertToVector256Int16.SByte.cs" /> + <Compile Include="ConvertToVector256UInt32.Byte.cs" /> + <Compile Include="ConvertToVector256Int32.Int16.cs" /> + <Compile Include="ConvertToVector256Int32.SByte.cs" /> + <Compile Include="ConvertToVector256UInt32.UInt16.cs" /> + <Compile Include="ConvertToVector256UInt64.Byte.cs" /> + <Compile Include="ConvertToVector256Int64.Int16.cs" /> + <Compile Include="ConvertToVector256Int64.Int32.cs" /> + <Compile Include="ConvertToVector256Int64.SByte.cs" /> + <Compile Include="ConvertToVector256UInt64.UInt16.cs" /> + <Compile Include="ConvertToVector256UInt64.UInt32.cs" /> + <Compile Include="Program.ConvertToVector256.cs" /> + <Compile Include="..\Shared\Program.cs" /> + <Compile Include="..\Shared\SimpleUnOpTest_DataTable.cs" /> + </ItemGroup> + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" /> + <PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' "></PropertyGroup> +</Project> diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx2/Max.Byte.cs b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/Max.Byte.cs new file mode 100644 index 0000000000..00af5a5699 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/Max.Byte.cs @@ -0,0 +1,330 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\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.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.X86; + +namespace JIT.HardwareIntrinsics.X86 +{ + public static partial class Program + { + private static void MaxByte() + { + var test = new SimpleBinaryOpTest__MaxByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + + // Validates basic functionality works, using LoadAligned + test.RunBasicScenario_LoadAligned(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + + // Validates calling via reflection works, using LoadAligned + test.RunReflectionScenario_LoadAligned(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + + // Validates passing a local works, using LoadAligned + test.RunLclVarScenario_LoadAligned(); + } + + // Validates passing the field of a local works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + 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 SimpleBinaryOpTest__MaxByte + { + private static readonly int LargestVectorSize = 32; + + private static readonly int Op1ElementCount = Unsafe.SizeOf<Vector256<Byte>>() / sizeof(Byte); + private static readonly int Op2ElementCount = Unsafe.SizeOf<Vector256<Byte>>() / sizeof(Byte); + private static readonly int RetElementCount = Unsafe.SizeOf<Vector256<Byte>>() / sizeof(Byte); + + private static Byte[] _data1 = new Byte[Op1ElementCount]; + private static Byte[] _data2 = new Byte[Op2ElementCount]; + + private static Vector256<Byte> _clsVar1; + private static Vector256<Byte> _clsVar2; + + private Vector256<Byte> _fld1; + private Vector256<Byte> _fld2; + + private SimpleBinaryOpTest__DataTable<Byte, Byte, Byte> _dataTable; + + static SimpleBinaryOpTest__MaxByte() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (byte)(random.Next(byte.MinValue, byte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<Byte>, byte>(ref _clsVar1), ref Unsafe.As<Byte, byte>(ref _data1[0]), (uint)Unsafe.SizeOf<Vector256<Byte>>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (byte)(random.Next(byte.MinValue, byte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<Byte>, byte>(ref _clsVar2), ref Unsafe.As<Byte, byte>(ref _data2[0]), (uint)Unsafe.SizeOf<Vector256<Byte>>()); + } + + public SimpleBinaryOpTest__MaxByte() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (byte)(random.Next(byte.MinValue, byte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<Byte>, byte>(ref _fld1), ref Unsafe.As<Byte, byte>(ref _data1[0]), (uint)Unsafe.SizeOf<Vector256<Byte>>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (byte)(random.Next(byte.MinValue, byte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<Byte>, byte>(ref _fld2), ref Unsafe.As<Byte, byte>(ref _data2[0]), (uint)Unsafe.SizeOf<Vector256<Byte>>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (byte)(random.Next(byte.MinValue, byte.MaxValue)); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (byte)(random.Next(byte.MinValue, byte.MaxValue)); } + _dataTable = new SimpleBinaryOpTest__DataTable<Byte, Byte, Byte>(_data1, _data2, new Byte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => Avx2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Avx2.Max( + Unsafe.Read<Vector256<Byte>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector256<Byte>>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Avx2.Max( + Avx.LoadVector256((Byte*)(_dataTable.inArray1Ptr)), + Avx.LoadVector256((Byte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Avx2.Max( + Avx.LoadAlignedVector256((Byte*)(_dataTable.inArray1Ptr)), + Avx.LoadAlignedVector256((Byte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.Max), new Type[] { typeof(Vector256<Byte>), typeof(Vector256<Byte>) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector256<Byte>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector256<Byte>>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<Byte>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.Max), new Type[] { typeof(Vector256<Byte>), typeof(Vector256<Byte>) }) + .Invoke(null, new object[] { + Avx.LoadVector256((Byte*)(_dataTable.inArray1Ptr)), + Avx.LoadVector256((Byte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<Byte>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.Max), new Type[] { typeof(Vector256<Byte>), typeof(Vector256<Byte>) }) + .Invoke(null, new object[] { + Avx.LoadAlignedVector256((Byte*)(_dataTable.inArray1Ptr)), + Avx.LoadAlignedVector256((Byte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<Byte>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Avx2.Max( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read<Vector256<Byte>>(_dataTable.inArray1Ptr); + var right = Unsafe.Read<Vector256<Byte>>(_dataTable.inArray2Ptr); + var result = Avx2.Max(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Avx.LoadVector256((Byte*)(_dataTable.inArray1Ptr)); + var right = Avx.LoadVector256((Byte*)(_dataTable.inArray2Ptr)); + var result = Avx2.Max(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Avx.LoadAlignedVector256((Byte*)(_dataTable.inArray1Ptr)); + var right = Avx.LoadAlignedVector256((Byte*)(_dataTable.inArray2Ptr)); + var result = Avx2.Max(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__MaxByte(); + var result = Avx2.Max(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Avx2.Max(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector256<Byte> left, Vector256<Byte> right, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + Byte[] inArray2 = new Byte[Op2ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As<Byte, byte>(ref inArray1[0]), left); + Unsafe.WriteUnaligned(ref Unsafe.As<Byte, byte>(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Byte, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), (uint)Unsafe.SizeOf<Vector256<Byte>>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + Byte[] inArray2 = new Byte[Op2ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Byte, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), (uint)Unsafe.SizeOf<Vector256<Byte>>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Byte, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), (uint)Unsafe.SizeOf<Vector256<Byte>>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Byte, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), (uint)Unsafe.SizeOf<Vector256<Byte>>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Byte[] left, Byte[] right, Byte[] result, [CallerMemberName] string method = "") + { + if (result[0] != Math.Max(left[0], right[0])) + { + Succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != Math.Max(left[i], right[i])) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Avx2)}.{nameof(Avx2.Max)}<Byte>(Vector256<Byte>, Vector256<Byte>): {method} failed:"); + Console.WriteLine($" left: ({string.Join(", ", left)})"); + Console.WriteLine($" right: ({string.Join(", ", right)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx2/Max.Int16.cs b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/Max.Int16.cs new file mode 100644 index 0000000000..bd8f391a29 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/Max.Int16.cs @@ -0,0 +1,330 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\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.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.X86; + +namespace JIT.HardwareIntrinsics.X86 +{ + public static partial class Program + { + private static void MaxInt16() + { + var test = new SimpleBinaryOpTest__MaxInt16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + + // Validates basic functionality works, using LoadAligned + test.RunBasicScenario_LoadAligned(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + + // Validates calling via reflection works, using LoadAligned + test.RunReflectionScenario_LoadAligned(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + + // Validates passing a local works, using LoadAligned + test.RunLclVarScenario_LoadAligned(); + } + + // Validates passing the field of a local works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + 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 SimpleBinaryOpTest__MaxInt16 + { + private static readonly int LargestVectorSize = 32; + + private static readonly int Op1ElementCount = Unsafe.SizeOf<Vector256<Int16>>() / sizeof(Int16); + private static readonly int Op2ElementCount = Unsafe.SizeOf<Vector256<Int16>>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf<Vector256<Int16>>() / sizeof(Int16); + + private static Int16[] _data1 = new Int16[Op1ElementCount]; + private static Int16[] _data2 = new Int16[Op2ElementCount]; + + private static Vector256<Int16> _clsVar1; + private static Vector256<Int16> _clsVar2; + + private Vector256<Int16> _fld1; + private Vector256<Int16> _fld2; + + private SimpleBinaryOpTest__DataTable<Int16, Int16, Int16> _dataTable; + + static SimpleBinaryOpTest__MaxInt16() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (short)(random.Next(short.MinValue, short.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<Int16>, byte>(ref _clsVar1), ref Unsafe.As<Int16, byte>(ref _data1[0]), (uint)Unsafe.SizeOf<Vector256<Int16>>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (short)(random.Next(short.MinValue, short.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<Int16>, byte>(ref _clsVar2), ref Unsafe.As<Int16, byte>(ref _data2[0]), (uint)Unsafe.SizeOf<Vector256<Int16>>()); + } + + public SimpleBinaryOpTest__MaxInt16() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (short)(random.Next(short.MinValue, short.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<Int16>, byte>(ref _fld1), ref Unsafe.As<Int16, byte>(ref _data1[0]), (uint)Unsafe.SizeOf<Vector256<Int16>>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (short)(random.Next(short.MinValue, short.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<Int16>, byte>(ref _fld2), ref Unsafe.As<Int16, byte>(ref _data2[0]), (uint)Unsafe.SizeOf<Vector256<Int16>>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (short)(random.Next(short.MinValue, short.MaxValue)); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (short)(random.Next(short.MinValue, short.MaxValue)); } + _dataTable = new SimpleBinaryOpTest__DataTable<Int16, Int16, Int16>(_data1, _data2, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => Avx2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Avx2.Max( + Unsafe.Read<Vector256<Int16>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector256<Int16>>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Avx2.Max( + Avx.LoadVector256((Int16*)(_dataTable.inArray1Ptr)), + Avx.LoadVector256((Int16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Avx2.Max( + Avx.LoadAlignedVector256((Int16*)(_dataTable.inArray1Ptr)), + Avx.LoadAlignedVector256((Int16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.Max), new Type[] { typeof(Vector256<Int16>), typeof(Vector256<Int16>) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector256<Int16>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector256<Int16>>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<Int16>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.Max), new Type[] { typeof(Vector256<Int16>), typeof(Vector256<Int16>) }) + .Invoke(null, new object[] { + Avx.LoadVector256((Int16*)(_dataTable.inArray1Ptr)), + Avx.LoadVector256((Int16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<Int16>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.Max), new Type[] { typeof(Vector256<Int16>), typeof(Vector256<Int16>) }) + .Invoke(null, new object[] { + Avx.LoadAlignedVector256((Int16*)(_dataTable.inArray1Ptr)), + Avx.LoadAlignedVector256((Int16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<Int16>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Avx2.Max( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read<Vector256<Int16>>(_dataTable.inArray1Ptr); + var right = Unsafe.Read<Vector256<Int16>>(_dataTable.inArray2Ptr); + var result = Avx2.Max(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Avx.LoadVector256((Int16*)(_dataTable.inArray1Ptr)); + var right = Avx.LoadVector256((Int16*)(_dataTable.inArray2Ptr)); + var result = Avx2.Max(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Avx.LoadAlignedVector256((Int16*)(_dataTable.inArray1Ptr)); + var right = Avx.LoadAlignedVector256((Int16*)(_dataTable.inArray2Ptr)); + var result = Avx2.Max(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__MaxInt16(); + var result = Avx2.Max(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Avx2.Max(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector256<Int16> left, Vector256<Int16> right, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As<Int16, byte>(ref inArray1[0]), left); + Unsafe.WriteUnaligned(ref Unsafe.As<Int16, byte>(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int16, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), (uint)Unsafe.SizeOf<Vector256<Int16>>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int16, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), (uint)Unsafe.SizeOf<Vector256<Int16>>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int16, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), (uint)Unsafe.SizeOf<Vector256<Int16>>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int16, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), (uint)Unsafe.SizeOf<Vector256<Int16>>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int16[] left, Int16[] right, Int16[] result, [CallerMemberName] string method = "") + { + if (result[0] != Math.Max(left[0], right[0])) + { + Succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != Math.Max(left[i], right[i])) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Avx2)}.{nameof(Avx2.Max)}<Int16>(Vector256<Int16>, Vector256<Int16>): {method} failed:"); + Console.WriteLine($" left: ({string.Join(", ", left)})"); + Console.WriteLine($" right: ({string.Join(", ", right)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx2/Max.Int32.cs b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/Max.Int32.cs new file mode 100644 index 0000000000..e9c45952b0 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/Max.Int32.cs @@ -0,0 +1,330 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\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.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.X86; + +namespace JIT.HardwareIntrinsics.X86 +{ + public static partial class Program + { + private static void MaxInt32() + { + var test = new SimpleBinaryOpTest__MaxInt32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + + // Validates basic functionality works, using LoadAligned + test.RunBasicScenario_LoadAligned(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + + // Validates calling via reflection works, using LoadAligned + test.RunReflectionScenario_LoadAligned(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + + // Validates passing a local works, using LoadAligned + test.RunLclVarScenario_LoadAligned(); + } + + // Validates passing the field of a local works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + 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 SimpleBinaryOpTest__MaxInt32 + { + private static readonly int LargestVectorSize = 32; + + private static readonly int Op1ElementCount = Unsafe.SizeOf<Vector256<Int32>>() / sizeof(Int32); + private static readonly int Op2ElementCount = Unsafe.SizeOf<Vector256<Int32>>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf<Vector256<Int32>>() / sizeof(Int32); + + private static Int32[] _data1 = new Int32[Op1ElementCount]; + private static Int32[] _data2 = new Int32[Op2ElementCount]; + + private static Vector256<Int32> _clsVar1; + private static Vector256<Int32> _clsVar2; + + private Vector256<Int32> _fld1; + private Vector256<Int32> _fld2; + + private SimpleBinaryOpTest__DataTable<Int32, Int32, Int32> _dataTable; + + static SimpleBinaryOpTest__MaxInt32() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (int)(random.Next(int.MinValue, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<Int32>, byte>(ref _clsVar1), ref Unsafe.As<Int32, byte>(ref _data1[0]), (uint)Unsafe.SizeOf<Vector256<Int32>>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (int)(random.Next(int.MinValue, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<Int32>, byte>(ref _clsVar2), ref Unsafe.As<Int32, byte>(ref _data2[0]), (uint)Unsafe.SizeOf<Vector256<Int32>>()); + } + + public SimpleBinaryOpTest__MaxInt32() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (int)(random.Next(int.MinValue, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<Int32>, byte>(ref _fld1), ref Unsafe.As<Int32, byte>(ref _data1[0]), (uint)Unsafe.SizeOf<Vector256<Int32>>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (int)(random.Next(int.MinValue, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<Int32>, byte>(ref _fld2), ref Unsafe.As<Int32, byte>(ref _data2[0]), (uint)Unsafe.SizeOf<Vector256<Int32>>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (int)(random.Next(int.MinValue, int.MaxValue)); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (int)(random.Next(int.MinValue, int.MaxValue)); } + _dataTable = new SimpleBinaryOpTest__DataTable<Int32, Int32, Int32>(_data1, _data2, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => Avx2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Avx2.Max( + Unsafe.Read<Vector256<Int32>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector256<Int32>>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Avx2.Max( + Avx.LoadVector256((Int32*)(_dataTable.inArray1Ptr)), + Avx.LoadVector256((Int32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Avx2.Max( + Avx.LoadAlignedVector256((Int32*)(_dataTable.inArray1Ptr)), + Avx.LoadAlignedVector256((Int32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.Max), new Type[] { typeof(Vector256<Int32>), typeof(Vector256<Int32>) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector256<Int32>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector256<Int32>>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<Int32>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.Max), new Type[] { typeof(Vector256<Int32>), typeof(Vector256<Int32>) }) + .Invoke(null, new object[] { + Avx.LoadVector256((Int32*)(_dataTable.inArray1Ptr)), + Avx.LoadVector256((Int32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<Int32>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.Max), new Type[] { typeof(Vector256<Int32>), typeof(Vector256<Int32>) }) + .Invoke(null, new object[] { + Avx.LoadAlignedVector256((Int32*)(_dataTable.inArray1Ptr)), + Avx.LoadAlignedVector256((Int32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<Int32>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Avx2.Max( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read<Vector256<Int32>>(_dataTable.inArray1Ptr); + var right = Unsafe.Read<Vector256<Int32>>(_dataTable.inArray2Ptr); + var result = Avx2.Max(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Avx.LoadVector256((Int32*)(_dataTable.inArray1Ptr)); + var right = Avx.LoadVector256((Int32*)(_dataTable.inArray2Ptr)); + var result = Avx2.Max(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Avx.LoadAlignedVector256((Int32*)(_dataTable.inArray1Ptr)); + var right = Avx.LoadAlignedVector256((Int32*)(_dataTable.inArray2Ptr)); + var result = Avx2.Max(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__MaxInt32(); + var result = Avx2.Max(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Avx2.Max(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector256<Int32> left, Vector256<Int32> right, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As<Int32, byte>(ref inArray1[0]), left); + Unsafe.WriteUnaligned(ref Unsafe.As<Int32, byte>(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int32, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), (uint)Unsafe.SizeOf<Vector256<Int32>>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int32, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), (uint)Unsafe.SizeOf<Vector256<Int32>>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int32, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), (uint)Unsafe.SizeOf<Vector256<Int32>>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int32, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), (uint)Unsafe.SizeOf<Vector256<Int32>>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int32[] left, Int32[] right, Int32[] result, [CallerMemberName] string method = "") + { + if (result[0] != Math.Max(left[0], right[0])) + { + Succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != Math.Max(left[i], right[i])) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Avx2)}.{nameof(Avx2.Max)}<Int32>(Vector256<Int32>, Vector256<Int32>): {method} failed:"); + Console.WriteLine($" left: ({string.Join(", ", left)})"); + Console.WriteLine($" right: ({string.Join(", ", right)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx2/Max.SByte.cs b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/Max.SByte.cs new file mode 100644 index 0000000000..cf8f8095af --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/Max.SByte.cs @@ -0,0 +1,330 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\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.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.X86; + +namespace JIT.HardwareIntrinsics.X86 +{ + public static partial class Program + { + private static void MaxSByte() + { + var test = new SimpleBinaryOpTest__MaxSByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + + // Validates basic functionality works, using LoadAligned + test.RunBasicScenario_LoadAligned(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + + // Validates calling via reflection works, using LoadAligned + test.RunReflectionScenario_LoadAligned(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + + // Validates passing a local works, using LoadAligned + test.RunLclVarScenario_LoadAligned(); + } + + // Validates passing the field of a local works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + 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 SimpleBinaryOpTest__MaxSByte + { + private static readonly int LargestVectorSize = 32; + + private static readonly int Op1ElementCount = Unsafe.SizeOf<Vector256<SByte>>() / sizeof(SByte); + private static readonly int Op2ElementCount = Unsafe.SizeOf<Vector256<SByte>>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf<Vector256<SByte>>() / sizeof(SByte); + + private static SByte[] _data1 = new SByte[Op1ElementCount]; + private static SByte[] _data2 = new SByte[Op2ElementCount]; + + private static Vector256<SByte> _clsVar1; + private static Vector256<SByte> _clsVar2; + + private Vector256<SByte> _fld1; + private Vector256<SByte> _fld2; + + private SimpleBinaryOpTest__DataTable<SByte, SByte, SByte> _dataTable; + + static SimpleBinaryOpTest__MaxSByte() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<SByte>, byte>(ref _clsVar1), ref Unsafe.As<SByte, byte>(ref _data1[0]), (uint)Unsafe.SizeOf<Vector256<SByte>>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<SByte>, byte>(ref _clsVar2), ref Unsafe.As<SByte, byte>(ref _data2[0]), (uint)Unsafe.SizeOf<Vector256<SByte>>()); + } + + public SimpleBinaryOpTest__MaxSByte() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<SByte>, byte>(ref _fld1), ref Unsafe.As<SByte, byte>(ref _data1[0]), (uint)Unsafe.SizeOf<Vector256<SByte>>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<SByte>, byte>(ref _fld2), ref Unsafe.As<SByte, byte>(ref _data2[0]), (uint)Unsafe.SizeOf<Vector256<SByte>>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue)); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue)); } + _dataTable = new SimpleBinaryOpTest__DataTable<SByte, SByte, SByte>(_data1, _data2, new SByte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => Avx2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Avx2.Max( + Unsafe.Read<Vector256<SByte>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector256<SByte>>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Avx2.Max( + Avx.LoadVector256((SByte*)(_dataTable.inArray1Ptr)), + Avx.LoadVector256((SByte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Avx2.Max( + Avx.LoadAlignedVector256((SByte*)(_dataTable.inArray1Ptr)), + Avx.LoadAlignedVector256((SByte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.Max), new Type[] { typeof(Vector256<SByte>), typeof(Vector256<SByte>) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector256<SByte>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector256<SByte>>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<SByte>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.Max), new Type[] { typeof(Vector256<SByte>), typeof(Vector256<SByte>) }) + .Invoke(null, new object[] { + Avx.LoadVector256((SByte*)(_dataTable.inArray1Ptr)), + Avx.LoadVector256((SByte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<SByte>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.Max), new Type[] { typeof(Vector256<SByte>), typeof(Vector256<SByte>) }) + .Invoke(null, new object[] { + Avx.LoadAlignedVector256((SByte*)(_dataTable.inArray1Ptr)), + Avx.LoadAlignedVector256((SByte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<SByte>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Avx2.Max( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read<Vector256<SByte>>(_dataTable.inArray1Ptr); + var right = Unsafe.Read<Vector256<SByte>>(_dataTable.inArray2Ptr); + var result = Avx2.Max(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Avx.LoadVector256((SByte*)(_dataTable.inArray1Ptr)); + var right = Avx.LoadVector256((SByte*)(_dataTable.inArray2Ptr)); + var result = Avx2.Max(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Avx.LoadAlignedVector256((SByte*)(_dataTable.inArray1Ptr)); + var right = Avx.LoadAlignedVector256((SByte*)(_dataTable.inArray2Ptr)); + var result = Avx2.Max(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__MaxSByte(); + var result = Avx2.Max(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Avx2.Max(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector256<SByte> left, Vector256<SByte> right, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As<SByte, byte>(ref inArray1[0]), left); + Unsafe.WriteUnaligned(ref Unsafe.As<SByte, byte>(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<SByte, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), (uint)Unsafe.SizeOf<Vector256<SByte>>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<SByte, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), (uint)Unsafe.SizeOf<Vector256<SByte>>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<SByte, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), (uint)Unsafe.SizeOf<Vector256<SByte>>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<SByte, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), (uint)Unsafe.SizeOf<Vector256<SByte>>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(SByte[] left, SByte[] right, SByte[] result, [CallerMemberName] string method = "") + { + if (result[0] != Math.Max(left[0], right[0])) + { + Succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != Math.Max(left[i], right[i])) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Avx2)}.{nameof(Avx2.Max)}<SByte>(Vector256<SByte>, Vector256<SByte>): {method} failed:"); + Console.WriteLine($" left: ({string.Join(", ", left)})"); + Console.WriteLine($" right: ({string.Join(", ", right)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx2/Max.UInt16.cs b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/Max.UInt16.cs new file mode 100644 index 0000000000..147cddaf5b --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/Max.UInt16.cs @@ -0,0 +1,330 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\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.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.X86; + +namespace JIT.HardwareIntrinsics.X86 +{ + public static partial class Program + { + private static void MaxUInt16() + { + var test = new SimpleBinaryOpTest__MaxUInt16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + + // Validates basic functionality works, using LoadAligned + test.RunBasicScenario_LoadAligned(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + + // Validates calling via reflection works, using LoadAligned + test.RunReflectionScenario_LoadAligned(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + + // Validates passing a local works, using LoadAligned + test.RunLclVarScenario_LoadAligned(); + } + + // Validates passing the field of a local works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + 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 SimpleBinaryOpTest__MaxUInt16 + { + private static readonly int LargestVectorSize = 32; + + private static readonly int Op1ElementCount = Unsafe.SizeOf<Vector256<UInt16>>() / sizeof(UInt16); + private static readonly int Op2ElementCount = Unsafe.SizeOf<Vector256<UInt16>>() / sizeof(UInt16); + private static readonly int RetElementCount = Unsafe.SizeOf<Vector256<UInt16>>() / sizeof(UInt16); + + private static UInt16[] _data1 = new UInt16[Op1ElementCount]; + private static UInt16[] _data2 = new UInt16[Op2ElementCount]; + + private static Vector256<UInt16> _clsVar1; + private static Vector256<UInt16> _clsVar2; + + private Vector256<UInt16> _fld1; + private Vector256<UInt16> _fld2; + + private SimpleBinaryOpTest__DataTable<UInt16, UInt16, UInt16> _dataTable; + + static SimpleBinaryOpTest__MaxUInt16() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (ushort)(random.Next(0, ushort.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<UInt16>, byte>(ref _clsVar1), ref Unsafe.As<UInt16, byte>(ref _data1[0]), (uint)Unsafe.SizeOf<Vector256<UInt16>>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (ushort)(random.Next(0, ushort.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<UInt16>, byte>(ref _clsVar2), ref Unsafe.As<UInt16, byte>(ref _data2[0]), (uint)Unsafe.SizeOf<Vector256<UInt16>>()); + } + + public SimpleBinaryOpTest__MaxUInt16() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (ushort)(random.Next(0, ushort.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<UInt16>, byte>(ref _fld1), ref Unsafe.As<UInt16, byte>(ref _data1[0]), (uint)Unsafe.SizeOf<Vector256<UInt16>>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (ushort)(random.Next(0, ushort.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<UInt16>, byte>(ref _fld2), ref Unsafe.As<UInt16, byte>(ref _data2[0]), (uint)Unsafe.SizeOf<Vector256<UInt16>>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (ushort)(random.Next(0, ushort.MaxValue)); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (ushort)(random.Next(0, ushort.MaxValue)); } + _dataTable = new SimpleBinaryOpTest__DataTable<UInt16, UInt16, UInt16>(_data1, _data2, new UInt16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => Avx2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Avx2.Max( + Unsafe.Read<Vector256<UInt16>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector256<UInt16>>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Avx2.Max( + Avx.LoadVector256((UInt16*)(_dataTable.inArray1Ptr)), + Avx.LoadVector256((UInt16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Avx2.Max( + Avx.LoadAlignedVector256((UInt16*)(_dataTable.inArray1Ptr)), + Avx.LoadAlignedVector256((UInt16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.Max), new Type[] { typeof(Vector256<UInt16>), typeof(Vector256<UInt16>) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector256<UInt16>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector256<UInt16>>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<UInt16>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.Max), new Type[] { typeof(Vector256<UInt16>), typeof(Vector256<UInt16>) }) + .Invoke(null, new object[] { + Avx.LoadVector256((UInt16*)(_dataTable.inArray1Ptr)), + Avx.LoadVector256((UInt16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<UInt16>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.Max), new Type[] { typeof(Vector256<UInt16>), typeof(Vector256<UInt16>) }) + .Invoke(null, new object[] { + Avx.LoadAlignedVector256((UInt16*)(_dataTable.inArray1Ptr)), + Avx.LoadAlignedVector256((UInt16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<UInt16>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Avx2.Max( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read<Vector256<UInt16>>(_dataTable.inArray1Ptr); + var right = Unsafe.Read<Vector256<UInt16>>(_dataTable.inArray2Ptr); + var result = Avx2.Max(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Avx.LoadVector256((UInt16*)(_dataTable.inArray1Ptr)); + var right = Avx.LoadVector256((UInt16*)(_dataTable.inArray2Ptr)); + var result = Avx2.Max(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Avx.LoadAlignedVector256((UInt16*)(_dataTable.inArray1Ptr)); + var right = Avx.LoadAlignedVector256((UInt16*)(_dataTable.inArray2Ptr)); + var result = Avx2.Max(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__MaxUInt16(); + var result = Avx2.Max(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Avx2.Max(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector256<UInt16> left, Vector256<UInt16> right, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As<UInt16, byte>(ref inArray1[0]), left); + Unsafe.WriteUnaligned(ref Unsafe.As<UInt16, byte>(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt16, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), (uint)Unsafe.SizeOf<Vector256<UInt16>>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt16, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), (uint)Unsafe.SizeOf<Vector256<UInt16>>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt16, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), (uint)Unsafe.SizeOf<Vector256<UInt16>>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt16, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), (uint)Unsafe.SizeOf<Vector256<UInt16>>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt16[] left, UInt16[] right, UInt16[] result, [CallerMemberName] string method = "") + { + if (result[0] != Math.Max(left[0], right[0])) + { + Succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != Math.Max(left[i], right[i])) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Avx2)}.{nameof(Avx2.Max)}<UInt16>(Vector256<UInt16>, Vector256<UInt16>): {method} failed:"); + Console.WriteLine($" left: ({string.Join(", ", left)})"); + Console.WriteLine($" right: ({string.Join(", ", right)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx2/Max.UInt32.cs b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/Max.UInt32.cs new file mode 100644 index 0000000000..98982ff2f6 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/Max.UInt32.cs @@ -0,0 +1,330 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\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.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.X86; + +namespace JIT.HardwareIntrinsics.X86 +{ + public static partial class Program + { + private static void MaxUInt32() + { + var test = new SimpleBinaryOpTest__MaxUInt32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + + // Validates basic functionality works, using LoadAligned + test.RunBasicScenario_LoadAligned(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + + // Validates calling via reflection works, using LoadAligned + test.RunReflectionScenario_LoadAligned(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + + // Validates passing a local works, using LoadAligned + test.RunLclVarScenario_LoadAligned(); + } + + // Validates passing the field of a local works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + 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 SimpleBinaryOpTest__MaxUInt32 + { + private static readonly int LargestVectorSize = 32; + + private static readonly int Op1ElementCount = Unsafe.SizeOf<Vector256<UInt32>>() / sizeof(UInt32); + private static readonly int Op2ElementCount = Unsafe.SizeOf<Vector256<UInt32>>() / sizeof(UInt32); + private static readonly int RetElementCount = Unsafe.SizeOf<Vector256<UInt32>>() / sizeof(UInt32); + + private static UInt32[] _data1 = new UInt32[Op1ElementCount]; + private static UInt32[] _data2 = new UInt32[Op2ElementCount]; + + private static Vector256<UInt32> _clsVar1; + private static Vector256<UInt32> _clsVar2; + + private Vector256<UInt32> _fld1; + private Vector256<UInt32> _fld2; + + private SimpleBinaryOpTest__DataTable<UInt32, UInt32, UInt32> _dataTable; + + static SimpleBinaryOpTest__MaxUInt32() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (uint)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<UInt32>, byte>(ref _clsVar1), ref Unsafe.As<UInt32, byte>(ref _data1[0]), (uint)Unsafe.SizeOf<Vector256<UInt32>>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (uint)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<UInt32>, byte>(ref _clsVar2), ref Unsafe.As<UInt32, byte>(ref _data2[0]), (uint)Unsafe.SizeOf<Vector256<UInt32>>()); + } + + public SimpleBinaryOpTest__MaxUInt32() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (uint)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<UInt32>, byte>(ref _fld1), ref Unsafe.As<UInt32, byte>(ref _data1[0]), (uint)Unsafe.SizeOf<Vector256<UInt32>>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (uint)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<UInt32>, byte>(ref _fld2), ref Unsafe.As<UInt32, byte>(ref _data2[0]), (uint)Unsafe.SizeOf<Vector256<UInt32>>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (uint)(random.Next(0, int.MaxValue)); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (uint)(random.Next(0, int.MaxValue)); } + _dataTable = new SimpleBinaryOpTest__DataTable<UInt32, UInt32, UInt32>(_data1, _data2, new UInt32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => Avx2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Avx2.Max( + Unsafe.Read<Vector256<UInt32>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector256<UInt32>>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Avx2.Max( + Avx.LoadVector256((UInt32*)(_dataTable.inArray1Ptr)), + Avx.LoadVector256((UInt32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Avx2.Max( + Avx.LoadAlignedVector256((UInt32*)(_dataTable.inArray1Ptr)), + Avx.LoadAlignedVector256((UInt32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.Max), new Type[] { typeof(Vector256<UInt32>), typeof(Vector256<UInt32>) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector256<UInt32>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector256<UInt32>>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<UInt32>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.Max), new Type[] { typeof(Vector256<UInt32>), typeof(Vector256<UInt32>) }) + .Invoke(null, new object[] { + Avx.LoadVector256((UInt32*)(_dataTable.inArray1Ptr)), + Avx.LoadVector256((UInt32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<UInt32>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.Max), new Type[] { typeof(Vector256<UInt32>), typeof(Vector256<UInt32>) }) + .Invoke(null, new object[] { + Avx.LoadAlignedVector256((UInt32*)(_dataTable.inArray1Ptr)), + Avx.LoadAlignedVector256((UInt32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<UInt32>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Avx2.Max( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read<Vector256<UInt32>>(_dataTable.inArray1Ptr); + var right = Unsafe.Read<Vector256<UInt32>>(_dataTable.inArray2Ptr); + var result = Avx2.Max(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Avx.LoadVector256((UInt32*)(_dataTable.inArray1Ptr)); + var right = Avx.LoadVector256((UInt32*)(_dataTable.inArray2Ptr)); + var result = Avx2.Max(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Avx.LoadAlignedVector256((UInt32*)(_dataTable.inArray1Ptr)); + var right = Avx.LoadAlignedVector256((UInt32*)(_dataTable.inArray2Ptr)); + var result = Avx2.Max(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__MaxUInt32(); + var result = Avx2.Max(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Avx2.Max(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector256<UInt32> left, Vector256<UInt32> right, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As<UInt32, byte>(ref inArray1[0]), left); + Unsafe.WriteUnaligned(ref Unsafe.As<UInt32, byte>(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt32, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), (uint)Unsafe.SizeOf<Vector256<UInt32>>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt32, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), (uint)Unsafe.SizeOf<Vector256<UInt32>>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt32, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), (uint)Unsafe.SizeOf<Vector256<UInt32>>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt32, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), (uint)Unsafe.SizeOf<Vector256<UInt32>>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt32[] left, UInt32[] right, UInt32[] result, [CallerMemberName] string method = "") + { + if (result[0] != Math.Max(left[0], right[0])) + { + Succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != Math.Max(left[i], right[i])) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Avx2)}.{nameof(Avx2.Max)}<UInt32>(Vector256<UInt32>, Vector256<UInt32>): {method} failed:"); + Console.WriteLine($" left: ({string.Join(", ", left)})"); + Console.WriteLine($" right: ({string.Join(", ", right)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx2/Min.Byte.cs b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/Min.Byte.cs new file mode 100644 index 0000000000..1144fe86e9 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/Min.Byte.cs @@ -0,0 +1,330 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\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.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.X86; + +namespace JIT.HardwareIntrinsics.X86 +{ + public static partial class Program + { + private static void MinByte() + { + var test = new SimpleBinaryOpTest__MinByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + + // Validates basic functionality works, using LoadAligned + test.RunBasicScenario_LoadAligned(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + + // Validates calling via reflection works, using LoadAligned + test.RunReflectionScenario_LoadAligned(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + + // Validates passing a local works, using LoadAligned + test.RunLclVarScenario_LoadAligned(); + } + + // Validates passing the field of a local works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + 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 SimpleBinaryOpTest__MinByte + { + private static readonly int LargestVectorSize = 32; + + private static readonly int Op1ElementCount = Unsafe.SizeOf<Vector256<Byte>>() / sizeof(Byte); + private static readonly int Op2ElementCount = Unsafe.SizeOf<Vector256<Byte>>() / sizeof(Byte); + private static readonly int RetElementCount = Unsafe.SizeOf<Vector256<Byte>>() / sizeof(Byte); + + private static Byte[] _data1 = new Byte[Op1ElementCount]; + private static Byte[] _data2 = new Byte[Op2ElementCount]; + + private static Vector256<Byte> _clsVar1; + private static Vector256<Byte> _clsVar2; + + private Vector256<Byte> _fld1; + private Vector256<Byte> _fld2; + + private SimpleBinaryOpTest__DataTable<Byte, Byte, Byte> _dataTable; + + static SimpleBinaryOpTest__MinByte() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (byte)(random.Next(byte.MinValue, byte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<Byte>, byte>(ref _clsVar1), ref Unsafe.As<Byte, byte>(ref _data1[0]), (uint)Unsafe.SizeOf<Vector256<Byte>>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (byte)(random.Next(byte.MinValue, byte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<Byte>, byte>(ref _clsVar2), ref Unsafe.As<Byte, byte>(ref _data2[0]), (uint)Unsafe.SizeOf<Vector256<Byte>>()); + } + + public SimpleBinaryOpTest__MinByte() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (byte)(random.Next(byte.MinValue, byte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<Byte>, byte>(ref _fld1), ref Unsafe.As<Byte, byte>(ref _data1[0]), (uint)Unsafe.SizeOf<Vector256<Byte>>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (byte)(random.Next(byte.MinValue, byte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<Byte>, byte>(ref _fld2), ref Unsafe.As<Byte, byte>(ref _data2[0]), (uint)Unsafe.SizeOf<Vector256<Byte>>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (byte)(random.Next(byte.MinValue, byte.MaxValue)); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (byte)(random.Next(byte.MinValue, byte.MaxValue)); } + _dataTable = new SimpleBinaryOpTest__DataTable<Byte, Byte, Byte>(_data1, _data2, new Byte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => Avx2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Avx2.Min( + Unsafe.Read<Vector256<Byte>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector256<Byte>>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Avx2.Min( + Avx.LoadVector256((Byte*)(_dataTable.inArray1Ptr)), + Avx.LoadVector256((Byte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Avx2.Min( + Avx.LoadAlignedVector256((Byte*)(_dataTable.inArray1Ptr)), + Avx.LoadAlignedVector256((Byte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.Min), new Type[] { typeof(Vector256<Byte>), typeof(Vector256<Byte>) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector256<Byte>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector256<Byte>>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<Byte>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.Min), new Type[] { typeof(Vector256<Byte>), typeof(Vector256<Byte>) }) + .Invoke(null, new object[] { + Avx.LoadVector256((Byte*)(_dataTable.inArray1Ptr)), + Avx.LoadVector256((Byte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<Byte>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.Min), new Type[] { typeof(Vector256<Byte>), typeof(Vector256<Byte>) }) + .Invoke(null, new object[] { + Avx.LoadAlignedVector256((Byte*)(_dataTable.inArray1Ptr)), + Avx.LoadAlignedVector256((Byte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<Byte>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Avx2.Min( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read<Vector256<Byte>>(_dataTable.inArray1Ptr); + var right = Unsafe.Read<Vector256<Byte>>(_dataTable.inArray2Ptr); + var result = Avx2.Min(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Avx.LoadVector256((Byte*)(_dataTable.inArray1Ptr)); + var right = Avx.LoadVector256((Byte*)(_dataTable.inArray2Ptr)); + var result = Avx2.Min(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Avx.LoadAlignedVector256((Byte*)(_dataTable.inArray1Ptr)); + var right = Avx.LoadAlignedVector256((Byte*)(_dataTable.inArray2Ptr)); + var result = Avx2.Min(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__MinByte(); + var result = Avx2.Min(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Avx2.Min(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector256<Byte> left, Vector256<Byte> right, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + Byte[] inArray2 = new Byte[Op2ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As<Byte, byte>(ref inArray1[0]), left); + Unsafe.WriteUnaligned(ref Unsafe.As<Byte, byte>(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Byte, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), (uint)Unsafe.SizeOf<Vector256<Byte>>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + Byte[] inArray2 = new Byte[Op2ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Byte, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), (uint)Unsafe.SizeOf<Vector256<Byte>>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Byte, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), (uint)Unsafe.SizeOf<Vector256<Byte>>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Byte, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), (uint)Unsafe.SizeOf<Vector256<Byte>>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Byte[] left, Byte[] right, Byte[] result, [CallerMemberName] string method = "") + { + if (result[0] != Math.Min(left[0], right[0])) + { + Succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != Math.Min(left[i], right[i])) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Avx2)}.{nameof(Avx2.Min)}<Byte>(Vector256<Byte>, Vector256<Byte>): {method} failed:"); + Console.WriteLine($" left: ({string.Join(", ", left)})"); + Console.WriteLine($" right: ({string.Join(", ", right)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx2/Min.Int16.cs b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/Min.Int16.cs new file mode 100644 index 0000000000..5cd0fd5707 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/Min.Int16.cs @@ -0,0 +1,330 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\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.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.X86; + +namespace JIT.HardwareIntrinsics.X86 +{ + public static partial class Program + { + private static void MinInt16() + { + var test = new SimpleBinaryOpTest__MinInt16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + + // Validates basic functionality works, using LoadAligned + test.RunBasicScenario_LoadAligned(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + + // Validates calling via reflection works, using LoadAligned + test.RunReflectionScenario_LoadAligned(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + + // Validates passing a local works, using LoadAligned + test.RunLclVarScenario_LoadAligned(); + } + + // Validates passing the field of a local works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + 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 SimpleBinaryOpTest__MinInt16 + { + private static readonly int LargestVectorSize = 32; + + private static readonly int Op1ElementCount = Unsafe.SizeOf<Vector256<Int16>>() / sizeof(Int16); + private static readonly int Op2ElementCount = Unsafe.SizeOf<Vector256<Int16>>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf<Vector256<Int16>>() / sizeof(Int16); + + private static Int16[] _data1 = new Int16[Op1ElementCount]; + private static Int16[] _data2 = new Int16[Op2ElementCount]; + + private static Vector256<Int16> _clsVar1; + private static Vector256<Int16> _clsVar2; + + private Vector256<Int16> _fld1; + private Vector256<Int16> _fld2; + + private SimpleBinaryOpTest__DataTable<Int16, Int16, Int16> _dataTable; + + static SimpleBinaryOpTest__MinInt16() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (short)(random.Next(short.MinValue, short.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<Int16>, byte>(ref _clsVar1), ref Unsafe.As<Int16, byte>(ref _data1[0]), (uint)Unsafe.SizeOf<Vector256<Int16>>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (short)(random.Next(short.MinValue, short.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<Int16>, byte>(ref _clsVar2), ref Unsafe.As<Int16, byte>(ref _data2[0]), (uint)Unsafe.SizeOf<Vector256<Int16>>()); + } + + public SimpleBinaryOpTest__MinInt16() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (short)(random.Next(short.MinValue, short.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<Int16>, byte>(ref _fld1), ref Unsafe.As<Int16, byte>(ref _data1[0]), (uint)Unsafe.SizeOf<Vector256<Int16>>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (short)(random.Next(short.MinValue, short.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<Int16>, byte>(ref _fld2), ref Unsafe.As<Int16, byte>(ref _data2[0]), (uint)Unsafe.SizeOf<Vector256<Int16>>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (short)(random.Next(short.MinValue, short.MaxValue)); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (short)(random.Next(short.MinValue, short.MaxValue)); } + _dataTable = new SimpleBinaryOpTest__DataTable<Int16, Int16, Int16>(_data1, _data2, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => Avx2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Avx2.Min( + Unsafe.Read<Vector256<Int16>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector256<Int16>>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Avx2.Min( + Avx.LoadVector256((Int16*)(_dataTable.inArray1Ptr)), + Avx.LoadVector256((Int16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Avx2.Min( + Avx.LoadAlignedVector256((Int16*)(_dataTable.inArray1Ptr)), + Avx.LoadAlignedVector256((Int16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.Min), new Type[] { typeof(Vector256<Int16>), typeof(Vector256<Int16>) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector256<Int16>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector256<Int16>>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<Int16>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.Min), new Type[] { typeof(Vector256<Int16>), typeof(Vector256<Int16>) }) + .Invoke(null, new object[] { + Avx.LoadVector256((Int16*)(_dataTable.inArray1Ptr)), + Avx.LoadVector256((Int16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<Int16>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.Min), new Type[] { typeof(Vector256<Int16>), typeof(Vector256<Int16>) }) + .Invoke(null, new object[] { + Avx.LoadAlignedVector256((Int16*)(_dataTable.inArray1Ptr)), + Avx.LoadAlignedVector256((Int16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<Int16>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Avx2.Min( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read<Vector256<Int16>>(_dataTable.inArray1Ptr); + var right = Unsafe.Read<Vector256<Int16>>(_dataTable.inArray2Ptr); + var result = Avx2.Min(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Avx.LoadVector256((Int16*)(_dataTable.inArray1Ptr)); + var right = Avx.LoadVector256((Int16*)(_dataTable.inArray2Ptr)); + var result = Avx2.Min(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Avx.LoadAlignedVector256((Int16*)(_dataTable.inArray1Ptr)); + var right = Avx.LoadAlignedVector256((Int16*)(_dataTable.inArray2Ptr)); + var result = Avx2.Min(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__MinInt16(); + var result = Avx2.Min(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Avx2.Min(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector256<Int16> left, Vector256<Int16> right, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As<Int16, byte>(ref inArray1[0]), left); + Unsafe.WriteUnaligned(ref Unsafe.As<Int16, byte>(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int16, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), (uint)Unsafe.SizeOf<Vector256<Int16>>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int16, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), (uint)Unsafe.SizeOf<Vector256<Int16>>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int16, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), (uint)Unsafe.SizeOf<Vector256<Int16>>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int16, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), (uint)Unsafe.SizeOf<Vector256<Int16>>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int16[] left, Int16[] right, Int16[] result, [CallerMemberName] string method = "") + { + if (result[0] != Math.Min(left[0], right[0])) + { + Succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != Math.Min(left[i], right[i])) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Avx2)}.{nameof(Avx2.Min)}<Int16>(Vector256<Int16>, Vector256<Int16>): {method} failed:"); + Console.WriteLine($" left: ({string.Join(", ", left)})"); + Console.WriteLine($" right: ({string.Join(", ", right)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx2/Min.Int32.cs b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/Min.Int32.cs new file mode 100644 index 0000000000..280dbfaa70 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/Min.Int32.cs @@ -0,0 +1,330 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\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.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.X86; + +namespace JIT.HardwareIntrinsics.X86 +{ + public static partial class Program + { + private static void MinInt32() + { + var test = new SimpleBinaryOpTest__MinInt32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + + // Validates basic functionality works, using LoadAligned + test.RunBasicScenario_LoadAligned(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + + // Validates calling via reflection works, using LoadAligned + test.RunReflectionScenario_LoadAligned(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + + // Validates passing a local works, using LoadAligned + test.RunLclVarScenario_LoadAligned(); + } + + // Validates passing the field of a local works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + 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 SimpleBinaryOpTest__MinInt32 + { + private static readonly int LargestVectorSize = 32; + + private static readonly int Op1ElementCount = Unsafe.SizeOf<Vector256<Int32>>() / sizeof(Int32); + private static readonly int Op2ElementCount = Unsafe.SizeOf<Vector256<Int32>>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf<Vector256<Int32>>() / sizeof(Int32); + + private static Int32[] _data1 = new Int32[Op1ElementCount]; + private static Int32[] _data2 = new Int32[Op2ElementCount]; + + private static Vector256<Int32> _clsVar1; + private static Vector256<Int32> _clsVar2; + + private Vector256<Int32> _fld1; + private Vector256<Int32> _fld2; + + private SimpleBinaryOpTest__DataTable<Int32, Int32, Int32> _dataTable; + + static SimpleBinaryOpTest__MinInt32() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (int)(random.Next(int.MinValue, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<Int32>, byte>(ref _clsVar1), ref Unsafe.As<Int32, byte>(ref _data1[0]), (uint)Unsafe.SizeOf<Vector256<Int32>>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (int)(random.Next(int.MinValue, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<Int32>, byte>(ref _clsVar2), ref Unsafe.As<Int32, byte>(ref _data2[0]), (uint)Unsafe.SizeOf<Vector256<Int32>>()); + } + + public SimpleBinaryOpTest__MinInt32() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (int)(random.Next(int.MinValue, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<Int32>, byte>(ref _fld1), ref Unsafe.As<Int32, byte>(ref _data1[0]), (uint)Unsafe.SizeOf<Vector256<Int32>>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (int)(random.Next(int.MinValue, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<Int32>, byte>(ref _fld2), ref Unsafe.As<Int32, byte>(ref _data2[0]), (uint)Unsafe.SizeOf<Vector256<Int32>>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (int)(random.Next(int.MinValue, int.MaxValue)); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (int)(random.Next(int.MinValue, int.MaxValue)); } + _dataTable = new SimpleBinaryOpTest__DataTable<Int32, Int32, Int32>(_data1, _data2, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => Avx2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Avx2.Min( + Unsafe.Read<Vector256<Int32>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector256<Int32>>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Avx2.Min( + Avx.LoadVector256((Int32*)(_dataTable.inArray1Ptr)), + Avx.LoadVector256((Int32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Avx2.Min( + Avx.LoadAlignedVector256((Int32*)(_dataTable.inArray1Ptr)), + Avx.LoadAlignedVector256((Int32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.Min), new Type[] { typeof(Vector256<Int32>), typeof(Vector256<Int32>) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector256<Int32>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector256<Int32>>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<Int32>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.Min), new Type[] { typeof(Vector256<Int32>), typeof(Vector256<Int32>) }) + .Invoke(null, new object[] { + Avx.LoadVector256((Int32*)(_dataTable.inArray1Ptr)), + Avx.LoadVector256((Int32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<Int32>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.Min), new Type[] { typeof(Vector256<Int32>), typeof(Vector256<Int32>) }) + .Invoke(null, new object[] { + Avx.LoadAlignedVector256((Int32*)(_dataTable.inArray1Ptr)), + Avx.LoadAlignedVector256((Int32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<Int32>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Avx2.Min( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read<Vector256<Int32>>(_dataTable.inArray1Ptr); + var right = Unsafe.Read<Vector256<Int32>>(_dataTable.inArray2Ptr); + var result = Avx2.Min(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Avx.LoadVector256((Int32*)(_dataTable.inArray1Ptr)); + var right = Avx.LoadVector256((Int32*)(_dataTable.inArray2Ptr)); + var result = Avx2.Min(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Avx.LoadAlignedVector256((Int32*)(_dataTable.inArray1Ptr)); + var right = Avx.LoadAlignedVector256((Int32*)(_dataTable.inArray2Ptr)); + var result = Avx2.Min(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__MinInt32(); + var result = Avx2.Min(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Avx2.Min(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector256<Int32> left, Vector256<Int32> right, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As<Int32, byte>(ref inArray1[0]), left); + Unsafe.WriteUnaligned(ref Unsafe.As<Int32, byte>(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int32, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), (uint)Unsafe.SizeOf<Vector256<Int32>>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int32, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), (uint)Unsafe.SizeOf<Vector256<Int32>>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int32, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), (uint)Unsafe.SizeOf<Vector256<Int32>>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int32, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), (uint)Unsafe.SizeOf<Vector256<Int32>>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int32[] left, Int32[] right, Int32[] result, [CallerMemberName] string method = "") + { + if (result[0] != Math.Min(left[0], right[0])) + { + Succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != Math.Min(left[i], right[i])) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Avx2)}.{nameof(Avx2.Min)}<Int32>(Vector256<Int32>, Vector256<Int32>): {method} failed:"); + Console.WriteLine($" left: ({string.Join(", ", left)})"); + Console.WriteLine($" right: ({string.Join(", ", right)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx2/Min.SByte.cs b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/Min.SByte.cs new file mode 100644 index 0000000000..c2cd75a4a2 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/Min.SByte.cs @@ -0,0 +1,330 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\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.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.X86; + +namespace JIT.HardwareIntrinsics.X86 +{ + public static partial class Program + { + private static void MinSByte() + { + var test = new SimpleBinaryOpTest__MinSByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + + // Validates basic functionality works, using LoadAligned + test.RunBasicScenario_LoadAligned(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + + // Validates calling via reflection works, using LoadAligned + test.RunReflectionScenario_LoadAligned(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + + // Validates passing a local works, using LoadAligned + test.RunLclVarScenario_LoadAligned(); + } + + // Validates passing the field of a local works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + 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 SimpleBinaryOpTest__MinSByte + { + private static readonly int LargestVectorSize = 32; + + private static readonly int Op1ElementCount = Unsafe.SizeOf<Vector256<SByte>>() / sizeof(SByte); + private static readonly int Op2ElementCount = Unsafe.SizeOf<Vector256<SByte>>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf<Vector256<SByte>>() / sizeof(SByte); + + private static SByte[] _data1 = new SByte[Op1ElementCount]; + private static SByte[] _data2 = new SByte[Op2ElementCount]; + + private static Vector256<SByte> _clsVar1; + private static Vector256<SByte> _clsVar2; + + private Vector256<SByte> _fld1; + private Vector256<SByte> _fld2; + + private SimpleBinaryOpTest__DataTable<SByte, SByte, SByte> _dataTable; + + static SimpleBinaryOpTest__MinSByte() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<SByte>, byte>(ref _clsVar1), ref Unsafe.As<SByte, byte>(ref _data1[0]), (uint)Unsafe.SizeOf<Vector256<SByte>>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<SByte>, byte>(ref _clsVar2), ref Unsafe.As<SByte, byte>(ref _data2[0]), (uint)Unsafe.SizeOf<Vector256<SByte>>()); + } + + public SimpleBinaryOpTest__MinSByte() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<SByte>, byte>(ref _fld1), ref Unsafe.As<SByte, byte>(ref _data1[0]), (uint)Unsafe.SizeOf<Vector256<SByte>>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<SByte>, byte>(ref _fld2), ref Unsafe.As<SByte, byte>(ref _data2[0]), (uint)Unsafe.SizeOf<Vector256<SByte>>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue)); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue)); } + _dataTable = new SimpleBinaryOpTest__DataTable<SByte, SByte, SByte>(_data1, _data2, new SByte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => Avx2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Avx2.Min( + Unsafe.Read<Vector256<SByte>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector256<SByte>>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Avx2.Min( + Avx.LoadVector256((SByte*)(_dataTable.inArray1Ptr)), + Avx.LoadVector256((SByte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Avx2.Min( + Avx.LoadAlignedVector256((SByte*)(_dataTable.inArray1Ptr)), + Avx.LoadAlignedVector256((SByte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.Min), new Type[] { typeof(Vector256<SByte>), typeof(Vector256<SByte>) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector256<SByte>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector256<SByte>>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<SByte>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.Min), new Type[] { typeof(Vector256<SByte>), typeof(Vector256<SByte>) }) + .Invoke(null, new object[] { + Avx.LoadVector256((SByte*)(_dataTable.inArray1Ptr)), + Avx.LoadVector256((SByte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<SByte>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.Min), new Type[] { typeof(Vector256<SByte>), typeof(Vector256<SByte>) }) + .Invoke(null, new object[] { + Avx.LoadAlignedVector256((SByte*)(_dataTable.inArray1Ptr)), + Avx.LoadAlignedVector256((SByte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<SByte>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Avx2.Min( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read<Vector256<SByte>>(_dataTable.inArray1Ptr); + var right = Unsafe.Read<Vector256<SByte>>(_dataTable.inArray2Ptr); + var result = Avx2.Min(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Avx.LoadVector256((SByte*)(_dataTable.inArray1Ptr)); + var right = Avx.LoadVector256((SByte*)(_dataTable.inArray2Ptr)); + var result = Avx2.Min(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Avx.LoadAlignedVector256((SByte*)(_dataTable.inArray1Ptr)); + var right = Avx.LoadAlignedVector256((SByte*)(_dataTable.inArray2Ptr)); + var result = Avx2.Min(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__MinSByte(); + var result = Avx2.Min(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Avx2.Min(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector256<SByte> left, Vector256<SByte> right, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As<SByte, byte>(ref inArray1[0]), left); + Unsafe.WriteUnaligned(ref Unsafe.As<SByte, byte>(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<SByte, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), (uint)Unsafe.SizeOf<Vector256<SByte>>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<SByte, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), (uint)Unsafe.SizeOf<Vector256<SByte>>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<SByte, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), (uint)Unsafe.SizeOf<Vector256<SByte>>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<SByte, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), (uint)Unsafe.SizeOf<Vector256<SByte>>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(SByte[] left, SByte[] right, SByte[] result, [CallerMemberName] string method = "") + { + if (result[0] != Math.Min(left[0], right[0])) + { + Succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != Math.Min(left[i], right[i])) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Avx2)}.{nameof(Avx2.Min)}<SByte>(Vector256<SByte>, Vector256<SByte>): {method} failed:"); + Console.WriteLine($" left: ({string.Join(", ", left)})"); + Console.WriteLine($" right: ({string.Join(", ", right)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx2/Min.UInt16.cs b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/Min.UInt16.cs new file mode 100644 index 0000000000..9b07ddfd83 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/Min.UInt16.cs @@ -0,0 +1,330 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\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.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.X86; + +namespace JIT.HardwareIntrinsics.X86 +{ + public static partial class Program + { + private static void MinUInt16() + { + var test = new SimpleBinaryOpTest__MinUInt16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + + // Validates basic functionality works, using LoadAligned + test.RunBasicScenario_LoadAligned(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + + // Validates calling via reflection works, using LoadAligned + test.RunReflectionScenario_LoadAligned(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + + // Validates passing a local works, using LoadAligned + test.RunLclVarScenario_LoadAligned(); + } + + // Validates passing the field of a local works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + 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 SimpleBinaryOpTest__MinUInt16 + { + private static readonly int LargestVectorSize = 32; + + private static readonly int Op1ElementCount = Unsafe.SizeOf<Vector256<UInt16>>() / sizeof(UInt16); + private static readonly int Op2ElementCount = Unsafe.SizeOf<Vector256<UInt16>>() / sizeof(UInt16); + private static readonly int RetElementCount = Unsafe.SizeOf<Vector256<UInt16>>() / sizeof(UInt16); + + private static UInt16[] _data1 = new UInt16[Op1ElementCount]; + private static UInt16[] _data2 = new UInt16[Op2ElementCount]; + + private static Vector256<UInt16> _clsVar1; + private static Vector256<UInt16> _clsVar2; + + private Vector256<UInt16> _fld1; + private Vector256<UInt16> _fld2; + + private SimpleBinaryOpTest__DataTable<UInt16, UInt16, UInt16> _dataTable; + + static SimpleBinaryOpTest__MinUInt16() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (ushort)(random.Next(0, ushort.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<UInt16>, byte>(ref _clsVar1), ref Unsafe.As<UInt16, byte>(ref _data1[0]), (uint)Unsafe.SizeOf<Vector256<UInt16>>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (ushort)(random.Next(0, ushort.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<UInt16>, byte>(ref _clsVar2), ref Unsafe.As<UInt16, byte>(ref _data2[0]), (uint)Unsafe.SizeOf<Vector256<UInt16>>()); + } + + public SimpleBinaryOpTest__MinUInt16() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (ushort)(random.Next(0, ushort.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<UInt16>, byte>(ref _fld1), ref Unsafe.As<UInt16, byte>(ref _data1[0]), (uint)Unsafe.SizeOf<Vector256<UInt16>>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (ushort)(random.Next(0, ushort.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<UInt16>, byte>(ref _fld2), ref Unsafe.As<UInt16, byte>(ref _data2[0]), (uint)Unsafe.SizeOf<Vector256<UInt16>>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (ushort)(random.Next(0, ushort.MaxValue)); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (ushort)(random.Next(0, ushort.MaxValue)); } + _dataTable = new SimpleBinaryOpTest__DataTable<UInt16, UInt16, UInt16>(_data1, _data2, new UInt16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => Avx2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Avx2.Min( + Unsafe.Read<Vector256<UInt16>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector256<UInt16>>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Avx2.Min( + Avx.LoadVector256((UInt16*)(_dataTable.inArray1Ptr)), + Avx.LoadVector256((UInt16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Avx2.Min( + Avx.LoadAlignedVector256((UInt16*)(_dataTable.inArray1Ptr)), + Avx.LoadAlignedVector256((UInt16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.Min), new Type[] { typeof(Vector256<UInt16>), typeof(Vector256<UInt16>) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector256<UInt16>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector256<UInt16>>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<UInt16>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.Min), new Type[] { typeof(Vector256<UInt16>), typeof(Vector256<UInt16>) }) + .Invoke(null, new object[] { + Avx.LoadVector256((UInt16*)(_dataTable.inArray1Ptr)), + Avx.LoadVector256((UInt16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<UInt16>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.Min), new Type[] { typeof(Vector256<UInt16>), typeof(Vector256<UInt16>) }) + .Invoke(null, new object[] { + Avx.LoadAlignedVector256((UInt16*)(_dataTable.inArray1Ptr)), + Avx.LoadAlignedVector256((UInt16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<UInt16>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Avx2.Min( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read<Vector256<UInt16>>(_dataTable.inArray1Ptr); + var right = Unsafe.Read<Vector256<UInt16>>(_dataTable.inArray2Ptr); + var result = Avx2.Min(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Avx.LoadVector256((UInt16*)(_dataTable.inArray1Ptr)); + var right = Avx.LoadVector256((UInt16*)(_dataTable.inArray2Ptr)); + var result = Avx2.Min(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Avx.LoadAlignedVector256((UInt16*)(_dataTable.inArray1Ptr)); + var right = Avx.LoadAlignedVector256((UInt16*)(_dataTable.inArray2Ptr)); + var result = Avx2.Min(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__MinUInt16(); + var result = Avx2.Min(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Avx2.Min(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector256<UInt16> left, Vector256<UInt16> right, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As<UInt16, byte>(ref inArray1[0]), left); + Unsafe.WriteUnaligned(ref Unsafe.As<UInt16, byte>(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt16, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), (uint)Unsafe.SizeOf<Vector256<UInt16>>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt16, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), (uint)Unsafe.SizeOf<Vector256<UInt16>>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt16, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), (uint)Unsafe.SizeOf<Vector256<UInt16>>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt16, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), (uint)Unsafe.SizeOf<Vector256<UInt16>>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt16[] left, UInt16[] right, UInt16[] result, [CallerMemberName] string method = "") + { + if (result[0] != Math.Min(left[0], right[0])) + { + Succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != Math.Min(left[i], right[i])) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Avx2)}.{nameof(Avx2.Min)}<UInt16>(Vector256<UInt16>, Vector256<UInt16>): {method} failed:"); + Console.WriteLine($" left: ({string.Join(", ", left)})"); + Console.WriteLine($" right: ({string.Join(", ", right)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx2/Min.UInt32.cs b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/Min.UInt32.cs new file mode 100644 index 0000000000..8272e8582a --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/Min.UInt32.cs @@ -0,0 +1,330 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\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.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.X86; + +namespace JIT.HardwareIntrinsics.X86 +{ + public static partial class Program + { + private static void MinUInt32() + { + var test = new SimpleBinaryOpTest__MinUInt32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + + // Validates basic functionality works, using LoadAligned + test.RunBasicScenario_LoadAligned(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + + // Validates calling via reflection works, using LoadAligned + test.RunReflectionScenario_LoadAligned(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + + // Validates passing a local works, using LoadAligned + test.RunLclVarScenario_LoadAligned(); + } + + // Validates passing the field of a local works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + 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 SimpleBinaryOpTest__MinUInt32 + { + private static readonly int LargestVectorSize = 32; + + private static readonly int Op1ElementCount = Unsafe.SizeOf<Vector256<UInt32>>() / sizeof(UInt32); + private static readonly int Op2ElementCount = Unsafe.SizeOf<Vector256<UInt32>>() / sizeof(UInt32); + private static readonly int RetElementCount = Unsafe.SizeOf<Vector256<UInt32>>() / sizeof(UInt32); + + private static UInt32[] _data1 = new UInt32[Op1ElementCount]; + private static UInt32[] _data2 = new UInt32[Op2ElementCount]; + + private static Vector256<UInt32> _clsVar1; + private static Vector256<UInt32> _clsVar2; + + private Vector256<UInt32> _fld1; + private Vector256<UInt32> _fld2; + + private SimpleBinaryOpTest__DataTable<UInt32, UInt32, UInt32> _dataTable; + + static SimpleBinaryOpTest__MinUInt32() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (uint)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<UInt32>, byte>(ref _clsVar1), ref Unsafe.As<UInt32, byte>(ref _data1[0]), (uint)Unsafe.SizeOf<Vector256<UInt32>>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (uint)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<UInt32>, byte>(ref _clsVar2), ref Unsafe.As<UInt32, byte>(ref _data2[0]), (uint)Unsafe.SizeOf<Vector256<UInt32>>()); + } + + public SimpleBinaryOpTest__MinUInt32() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (uint)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<UInt32>, byte>(ref _fld1), ref Unsafe.As<UInt32, byte>(ref _data1[0]), (uint)Unsafe.SizeOf<Vector256<UInt32>>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (uint)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<UInt32>, byte>(ref _fld2), ref Unsafe.As<UInt32, byte>(ref _data2[0]), (uint)Unsafe.SizeOf<Vector256<UInt32>>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (uint)(random.Next(0, int.MaxValue)); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (uint)(random.Next(0, int.MaxValue)); } + _dataTable = new SimpleBinaryOpTest__DataTable<UInt32, UInt32, UInt32>(_data1, _data2, new UInt32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => Avx2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Avx2.Min( + Unsafe.Read<Vector256<UInt32>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector256<UInt32>>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Avx2.Min( + Avx.LoadVector256((UInt32*)(_dataTable.inArray1Ptr)), + Avx.LoadVector256((UInt32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Avx2.Min( + Avx.LoadAlignedVector256((UInt32*)(_dataTable.inArray1Ptr)), + Avx.LoadAlignedVector256((UInt32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.Min), new Type[] { typeof(Vector256<UInt32>), typeof(Vector256<UInt32>) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector256<UInt32>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector256<UInt32>>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<UInt32>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.Min), new Type[] { typeof(Vector256<UInt32>), typeof(Vector256<UInt32>) }) + .Invoke(null, new object[] { + Avx.LoadVector256((UInt32*)(_dataTable.inArray1Ptr)), + Avx.LoadVector256((UInt32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<UInt32>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.Min), new Type[] { typeof(Vector256<UInt32>), typeof(Vector256<UInt32>) }) + .Invoke(null, new object[] { + Avx.LoadAlignedVector256((UInt32*)(_dataTable.inArray1Ptr)), + Avx.LoadAlignedVector256((UInt32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<UInt32>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Avx2.Min( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read<Vector256<UInt32>>(_dataTable.inArray1Ptr); + var right = Unsafe.Read<Vector256<UInt32>>(_dataTable.inArray2Ptr); + var result = Avx2.Min(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Avx.LoadVector256((UInt32*)(_dataTable.inArray1Ptr)); + var right = Avx.LoadVector256((UInt32*)(_dataTable.inArray2Ptr)); + var result = Avx2.Min(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Avx.LoadAlignedVector256((UInt32*)(_dataTable.inArray1Ptr)); + var right = Avx.LoadAlignedVector256((UInt32*)(_dataTable.inArray2Ptr)); + var result = Avx2.Min(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__MinUInt32(); + var result = Avx2.Min(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Avx2.Min(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector256<UInt32> left, Vector256<UInt32> right, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As<UInt32, byte>(ref inArray1[0]), left); + Unsafe.WriteUnaligned(ref Unsafe.As<UInt32, byte>(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt32, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), (uint)Unsafe.SizeOf<Vector256<UInt32>>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt32, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), (uint)Unsafe.SizeOf<Vector256<UInt32>>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt32, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), (uint)Unsafe.SizeOf<Vector256<UInt32>>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt32, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), (uint)Unsafe.SizeOf<Vector256<UInt32>>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt32[] left, UInt32[] right, UInt32[] result, [CallerMemberName] string method = "") + { + if (result[0] != Math.Min(left[0], right[0])) + { + Succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != Math.Min(left[i], right[i])) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Avx2)}.{nameof(Avx2.Min)}<UInt32>(Vector256<UInt32>, Vector256<UInt32>): {method} failed:"); + Console.WriteLine($" left: ({string.Join(", ", left)})"); + Console.WriteLine($" right: ({string.Join(", ", right)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx2/MoveMask.cs b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/MoveMask.cs new file mode 100644 index 0000000000..c33b4f2562 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/MoveMask.cs @@ -0,0 +1,77 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. +// + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics.X86; +using System.Runtime.Intrinsics; + +namespace IntelHardwareIntrinsicTest +{ + class Program + { + const int Pass = 100; + const int Fail = 0; + + static unsafe int Main(string[] args) + { + int testResult = Pass; + + if (Avx2.IsSupported) + { + using (TestTable<byte> byteTable = new TestTable<byte>(new byte[32] { 255, 2, 0, 80, 0, 7, 0, 1, 2, 7, 80, 0, 123, 127, 5, 255, 255, 2, 0, 80, 0, 7, 0, 1, 2, 7, 80, 0, 123, 127, 5, 255 })) + { + + var vf1 = Unsafe.Read<Vector256<byte>>(byteTable.inArray1Ptr); + var res = Avx2.MoveMask(vf1); + + if (res != -2147385343) + { + Console.WriteLine("AVX2 MoveMask failed on byte:"); + Console.WriteLine(res); + testResult = Fail; + } + } + + using (TestTable<sbyte> sbyteTable = new TestTable<sbyte>(new sbyte[32] { -1, 2, 0, 6, 0, 7, 111, 1, 2, 55, 80, 0, 11, 127, 5, -9, -1, 2, 0, 6, 0, 7, 111, 1, 2, 55, 80, 0, 11, 127, 5, -9 })) + { + + var vf1 = Unsafe.Read<Vector256<sbyte>>(sbyteTable.inArray1Ptr); + var res = Avx2.MoveMask(vf1); + + if (res != -2147385343) + { + Console.WriteLine("AVX2 MoveMask failed on sbyte:"); + Console.WriteLine(res); + testResult = Fail; + } + } + } + + + return testResult; + } + + public unsafe struct TestTable<T> : IDisposable where T : struct + { + public T[] inArray1; + public void* inArray1Ptr => inHandle1.AddrOfPinnedObject().ToPointer(); + GCHandle inHandle1; + + public TestTable(T[] a) + { + this.inArray1 = a; + inHandle1 = GCHandle.Alloc(inArray1, GCHandleType.Pinned); + } + + public void Dispose() + { + inHandle1.Free(); + } + } + + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx2/MoveMask_r.csproj b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/MoveMask_r.csproj new file mode 100644 index 0000000000..868b0ce2e8 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/MoveMask_r.csproj @@ -0,0 +1,36 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" /> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> + <SchemaVersion>2.0</SchemaVersion> + <ProjectGuid>{EC7AD883-41EA-4BDC-BFBE-77A78B727D76}</ProjectGuid> + <OutputType>Exe</OutputType> + <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> + <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir> + <AllowUnsafeBlocks>true</AllowUnsafeBlocks> + </PropertyGroup> + <!-- Default configurations to help VS understand the configurations --> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' " /> + <ItemGroup> + <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies"> + <Visible>False</Visible> + </CodeAnalysisDependentAssemblyPaths> + </ItemGroup> + <PropertyGroup> + <DebugType>None</DebugType> + <Optimize>True</Optimize> + </PropertyGroup> + <ItemGroup> + <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" /> + </ItemGroup> + <ItemGroup> + <Compile Include="MoveMask.cs" /> + </ItemGroup> + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" /> + <PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' "> + </PropertyGroup> +</Project>
\ No newline at end of file diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx2/MoveMask_ro.csproj b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/MoveMask_ro.csproj new file mode 100644 index 0000000000..06ad5dc47f --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/MoveMask_ro.csproj @@ -0,0 +1,36 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" /> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> + <SchemaVersion>2.0</SchemaVersion> + <ProjectGuid>{4D4CC0B8-3894-4F6F-868B-C93A7B722B5C}</ProjectGuid> + <OutputType>Exe</OutputType> + <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> + <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir> + <AllowUnsafeBlocks>true</AllowUnsafeBlocks> + </PropertyGroup> + <!-- Default configurations to help VS understand the configurations --> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' " /> + <ItemGroup> + <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies"> + <Visible>False</Visible> + </CodeAnalysisDependentAssemblyPaths> + </ItemGroup> + <PropertyGroup> + <DebugType>None</DebugType> + <Optimize>True</Optimize> + </PropertyGroup> + <ItemGroup> + <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" /> + </ItemGroup> + <ItemGroup> + <Compile Include="MoveMask.cs" /> + </ItemGroup> + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" /> + <PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' "> + </PropertyGroup> +</Project> diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx2/Permute2x128.Avx2.cs b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/Permute2x128.Avx2.cs new file mode 100644 index 0000000000..056d7d0ea9 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/Permute2x128.Avx2.cs @@ -0,0 +1,22 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; + +namespace JIT.HardwareIntrinsics.X86 +{ + public static partial class Program + { + static Program() + { + TestList = new Dictionary<string, Action>() { + ["Permute2x128.Int32.2"] = Permute2x128Int322, + ["Permute2x128.UInt32.2"] = Permute2x128UInt322, + ["Permute2x128.Int64.2"] = Permute2x128Int642, + ["Permute2x128.UInt64.2"] = Permute2x128UInt642, + }; + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx2/Permute2x128.Int32.2.cs b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/Permute2x128.Int32.2.cs new file mode 100644 index 0000000000..1f650764e9 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/Permute2x128.Int32.2.cs @@ -0,0 +1,337 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\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.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.X86; + +namespace JIT.HardwareIntrinsics.X86 +{ + public static partial class Program + { + private static void Permute2x128Int322() + { + var test = new SimpleBinaryOpTest__Permute2x128Int322(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + + // Validates basic functionality works, using LoadAligned + test.RunBasicScenario_LoadAligned(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + + // Validates calling via reflection works, using LoadAligned + test.RunReflectionScenario_LoadAligned(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + + // Validates passing a local works, using LoadAligned + test.RunLclVarScenario_LoadAligned(); + } + + // Validates passing the field of a local works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + 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 SimpleBinaryOpTest__Permute2x128Int322 + { + private static readonly int LargestVectorSize = 32; + + private static readonly int Op1ElementCount = Unsafe.SizeOf<Vector256<Int32>>() / sizeof(Int32); + private static readonly int Op2ElementCount = Unsafe.SizeOf<Vector256<Int32>>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf<Vector256<Int32>>() / sizeof(Int32); + + private static Int32[] _data1 = new Int32[Op1ElementCount]; + private static Int32[] _data2 = new Int32[Op2ElementCount]; + + private static Vector256<Int32> _clsVar1; + private static Vector256<Int32> _clsVar2; + + private Vector256<Int32> _fld1; + private Vector256<Int32> _fld2; + + private SimpleBinaryOpTest__DataTable<Int32, Int32, Int32> _dataTable; + + static SimpleBinaryOpTest__Permute2x128Int322() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (int)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<Int32>, byte>(ref _clsVar1), ref Unsafe.As<Int32, byte>(ref _data1[0]), (uint)Unsafe.SizeOf<Vector256<Int32>>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (int)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<Int32>, byte>(ref _clsVar2), ref Unsafe.As<Int32, byte>(ref _data2[0]), (uint)Unsafe.SizeOf<Vector256<Int32>>()); + } + + public SimpleBinaryOpTest__Permute2x128Int322() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (int)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<Int32>, byte>(ref _fld1), ref Unsafe.As<Int32, byte>(ref _data1[0]), (uint)Unsafe.SizeOf<Vector256<Int32>>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (int)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<Int32>, byte>(ref _fld2), ref Unsafe.As<Int32, byte>(ref _data2[0]), (uint)Unsafe.SizeOf<Vector256<Int32>>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (int)(random.Next(0, int.MaxValue)); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (int)(random.Next(0, int.MaxValue)); } + _dataTable = new SimpleBinaryOpTest__DataTable<Int32, Int32, Int32>(_data1, _data2, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => Avx2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Avx2.Permute2x128( + Unsafe.Read<Vector256<Int32>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector256<Int32>>(_dataTable.inArray2Ptr), + 2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Avx2.Permute2x128( + Avx.LoadVector256((Int32*)(_dataTable.inArray1Ptr)), + Avx.LoadVector256((Int32*)(_dataTable.inArray2Ptr)), + 2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Avx2.Permute2x128( + Avx.LoadAlignedVector256((Int32*)(_dataTable.inArray1Ptr)), + Avx.LoadAlignedVector256((Int32*)(_dataTable.inArray2Ptr)), + 2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.Permute2x128), new Type[] { typeof(Vector256<Int32>), typeof(Vector256<Int32>), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector256<Int32>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector256<Int32>>(_dataTable.inArray2Ptr), + (byte)2 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<Int32>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.Permute2x128), new Type[] { typeof(Vector256<Int32>), typeof(Vector256<Int32>), typeof(byte) }) + .Invoke(null, new object[] { + Avx.LoadVector256((Int32*)(_dataTable.inArray1Ptr)), + Avx.LoadVector256((Int32*)(_dataTable.inArray2Ptr)), + (byte)2 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<Int32>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.Permute2x128), new Type[] { typeof(Vector256<Int32>), typeof(Vector256<Int32>), typeof(byte) }) + .Invoke(null, new object[] { + Avx.LoadAlignedVector256((Int32*)(_dataTable.inArray1Ptr)), + Avx.LoadAlignedVector256((Int32*)(_dataTable.inArray2Ptr)), + (byte)2 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<Int32>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Avx2.Permute2x128( + _clsVar1, + _clsVar2, + 2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read<Vector256<Int32>>(_dataTable.inArray1Ptr); + var right = Unsafe.Read<Vector256<Int32>>(_dataTable.inArray2Ptr); + var result = Avx2.Permute2x128(left, right, 2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Avx.LoadVector256((Int32*)(_dataTable.inArray1Ptr)); + var right = Avx.LoadVector256((Int32*)(_dataTable.inArray2Ptr)); + var result = Avx2.Permute2x128(left, right, 2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Avx.LoadAlignedVector256((Int32*)(_dataTable.inArray1Ptr)); + var right = Avx.LoadAlignedVector256((Int32*)(_dataTable.inArray2Ptr)); + var result = Avx2.Permute2x128(left, right, 2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__Permute2x128Int322(); + var result = Avx2.Permute2x128(test._fld1, test._fld2, 2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Avx2.Permute2x128(_fld1, _fld2, 2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector256<Int32> left, Vector256<Int32> right, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As<Int32, byte>(ref inArray1[0]), left); + Unsafe.WriteUnaligned(ref Unsafe.As<Int32, byte>(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int32, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), (uint)Unsafe.SizeOf<Vector256<Int32>>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int32, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), (uint)Unsafe.SizeOf<Vector256<Int32>>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int32, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), (uint)Unsafe.SizeOf<Vector256<Int32>>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int32, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), (uint)Unsafe.SizeOf<Vector256<Int32>>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int32[] left, Int32[] right, Int32[] result, [CallerMemberName] string method = "") + { + if (result[0] != right[0]) + { + Succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (i > 3 ? (result[i] != left[i - 4]) : (result[i] != right[i])) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Avx2)}.{nameof(Avx2.Permute2x128)}<Int32>(Vector256<Int32>.2, Vector256<Int32>): {method} failed:"); + Console.WriteLine($" left: ({string.Join(", ", left)})"); + Console.WriteLine($" right: ({string.Join(", ", right)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx2/Permute2x128.Int64.2.cs b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/Permute2x128.Int64.2.cs new file mode 100644 index 0000000000..0662227675 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/Permute2x128.Int64.2.cs @@ -0,0 +1,337 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\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.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.X86; + +namespace JIT.HardwareIntrinsics.X86 +{ + public static partial class Program + { + private static void Permute2x128Int642() + { + var test = new SimpleBinaryOpTest__Permute2x128Int642(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + + // Validates basic functionality works, using LoadAligned + test.RunBasicScenario_LoadAligned(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + + // Validates calling via reflection works, using LoadAligned + test.RunReflectionScenario_LoadAligned(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + + // Validates passing a local works, using LoadAligned + test.RunLclVarScenario_LoadAligned(); + } + + // Validates passing the field of a local works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + 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 SimpleBinaryOpTest__Permute2x128Int642 + { + private static readonly int LargestVectorSize = 32; + + private static readonly int Op1ElementCount = Unsafe.SizeOf<Vector256<Int64>>() / sizeof(Int64); + private static readonly int Op2ElementCount = Unsafe.SizeOf<Vector256<Int64>>() / sizeof(Int64); + private static readonly int RetElementCount = Unsafe.SizeOf<Vector256<Int64>>() / sizeof(Int64); + + private static Int64[] _data1 = new Int64[Op1ElementCount]; + private static Int64[] _data2 = new Int64[Op2ElementCount]; + + private static Vector256<Int64> _clsVar1; + private static Vector256<Int64> _clsVar2; + + private Vector256<Int64> _fld1; + private Vector256<Int64> _fld2; + + private SimpleBinaryOpTest__DataTable<Int64, Int64, Int64> _dataTable; + + static SimpleBinaryOpTest__Permute2x128Int642() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (long)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<Int64>, byte>(ref _clsVar1), ref Unsafe.As<Int64, byte>(ref _data1[0]), (uint)Unsafe.SizeOf<Vector256<Int64>>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (long)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<Int64>, byte>(ref _clsVar2), ref Unsafe.As<Int64, byte>(ref _data2[0]), (uint)Unsafe.SizeOf<Vector256<Int64>>()); + } + + public SimpleBinaryOpTest__Permute2x128Int642() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (long)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<Int64>, byte>(ref _fld1), ref Unsafe.As<Int64, byte>(ref _data1[0]), (uint)Unsafe.SizeOf<Vector256<Int64>>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (long)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<Int64>, byte>(ref _fld2), ref Unsafe.As<Int64, byte>(ref _data2[0]), (uint)Unsafe.SizeOf<Vector256<Int64>>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (long)(random.Next(0, int.MaxValue)); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (long)(random.Next(0, int.MaxValue)); } + _dataTable = new SimpleBinaryOpTest__DataTable<Int64, Int64, Int64>(_data1, _data2, new Int64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => Avx2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Avx2.Permute2x128( + Unsafe.Read<Vector256<Int64>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector256<Int64>>(_dataTable.inArray2Ptr), + 2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Avx2.Permute2x128( + Avx.LoadVector256((Int64*)(_dataTable.inArray1Ptr)), + Avx.LoadVector256((Int64*)(_dataTable.inArray2Ptr)), + 2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Avx2.Permute2x128( + Avx.LoadAlignedVector256((Int64*)(_dataTable.inArray1Ptr)), + Avx.LoadAlignedVector256((Int64*)(_dataTable.inArray2Ptr)), + 2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.Permute2x128), new Type[] { typeof(Vector256<Int64>), typeof(Vector256<Int64>), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector256<Int64>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector256<Int64>>(_dataTable.inArray2Ptr), + (byte)2 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<Int64>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.Permute2x128), new Type[] { typeof(Vector256<Int64>), typeof(Vector256<Int64>), typeof(byte) }) + .Invoke(null, new object[] { + Avx.LoadVector256((Int64*)(_dataTable.inArray1Ptr)), + Avx.LoadVector256((Int64*)(_dataTable.inArray2Ptr)), + (byte)2 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<Int64>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.Permute2x128), new Type[] { typeof(Vector256<Int64>), typeof(Vector256<Int64>), typeof(byte) }) + .Invoke(null, new object[] { + Avx.LoadAlignedVector256((Int64*)(_dataTable.inArray1Ptr)), + Avx.LoadAlignedVector256((Int64*)(_dataTable.inArray2Ptr)), + (byte)2 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<Int64>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Avx2.Permute2x128( + _clsVar1, + _clsVar2, + 2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read<Vector256<Int64>>(_dataTable.inArray1Ptr); + var right = Unsafe.Read<Vector256<Int64>>(_dataTable.inArray2Ptr); + var result = Avx2.Permute2x128(left, right, 2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Avx.LoadVector256((Int64*)(_dataTable.inArray1Ptr)); + var right = Avx.LoadVector256((Int64*)(_dataTable.inArray2Ptr)); + var result = Avx2.Permute2x128(left, right, 2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Avx.LoadAlignedVector256((Int64*)(_dataTable.inArray1Ptr)); + var right = Avx.LoadAlignedVector256((Int64*)(_dataTable.inArray2Ptr)); + var result = Avx2.Permute2x128(left, right, 2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__Permute2x128Int642(); + var result = Avx2.Permute2x128(test._fld1, test._fld2, 2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Avx2.Permute2x128(_fld1, _fld2, 2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector256<Int64> left, Vector256<Int64> right, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As<Int64, byte>(ref inArray1[0]), left); + Unsafe.WriteUnaligned(ref Unsafe.As<Int64, byte>(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int64, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), (uint)Unsafe.SizeOf<Vector256<Int64>>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int64, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), (uint)Unsafe.SizeOf<Vector256<Int64>>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int64, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), (uint)Unsafe.SizeOf<Vector256<Int64>>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int64, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), (uint)Unsafe.SizeOf<Vector256<Int64>>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int64[] left, Int64[] right, Int64[] result, [CallerMemberName] string method = "") + { + if (result[0] != right[0]) + { + Succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (i > 1 ? (result[i] != left[i - 2]) : (result[i] != right[i])) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Avx2)}.{nameof(Avx2.Permute2x128)}<Int64>(Vector256<Int64>.2, Vector256<Int64>): {method} failed:"); + Console.WriteLine($" left: ({string.Join(", ", left)})"); + Console.WriteLine($" right: ({string.Join(", ", right)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx2/Permute2x128.UInt32.2.cs b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/Permute2x128.UInt32.2.cs new file mode 100644 index 0000000000..ca46e060b0 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/Permute2x128.UInt32.2.cs @@ -0,0 +1,337 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\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.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.X86; + +namespace JIT.HardwareIntrinsics.X86 +{ + public static partial class Program + { + private static void Permute2x128UInt322() + { + var test = new SimpleBinaryOpTest__Permute2x128UInt322(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + + // Validates basic functionality works, using LoadAligned + test.RunBasicScenario_LoadAligned(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + + // Validates calling via reflection works, using LoadAligned + test.RunReflectionScenario_LoadAligned(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + + // Validates passing a local works, using LoadAligned + test.RunLclVarScenario_LoadAligned(); + } + + // Validates passing the field of a local works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + 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 SimpleBinaryOpTest__Permute2x128UInt322 + { + private static readonly int LargestVectorSize = 32; + + private static readonly int Op1ElementCount = Unsafe.SizeOf<Vector256<UInt32>>() / sizeof(UInt32); + private static readonly int Op2ElementCount = Unsafe.SizeOf<Vector256<UInt32>>() / sizeof(UInt32); + private static readonly int RetElementCount = Unsafe.SizeOf<Vector256<UInt32>>() / sizeof(UInt32); + + private static UInt32[] _data1 = new UInt32[Op1ElementCount]; + private static UInt32[] _data2 = new UInt32[Op2ElementCount]; + + private static Vector256<UInt32> _clsVar1; + private static Vector256<UInt32> _clsVar2; + + private Vector256<UInt32> _fld1; + private Vector256<UInt32> _fld2; + + private SimpleBinaryOpTest__DataTable<UInt32, UInt32, UInt32> _dataTable; + + static SimpleBinaryOpTest__Permute2x128UInt322() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (uint)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<UInt32>, byte>(ref _clsVar1), ref Unsafe.As<UInt32, byte>(ref _data1[0]), (uint)Unsafe.SizeOf<Vector256<UInt32>>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (uint)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<UInt32>, byte>(ref _clsVar2), ref Unsafe.As<UInt32, byte>(ref _data2[0]), (uint)Unsafe.SizeOf<Vector256<UInt32>>()); + } + + public SimpleBinaryOpTest__Permute2x128UInt322() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (uint)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<UInt32>, byte>(ref _fld1), ref Unsafe.As<UInt32, byte>(ref _data1[0]), (uint)Unsafe.SizeOf<Vector256<UInt32>>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (uint)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<UInt32>, byte>(ref _fld2), ref Unsafe.As<UInt32, byte>(ref _data2[0]), (uint)Unsafe.SizeOf<Vector256<UInt32>>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (uint)(random.Next(0, int.MaxValue)); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (uint)(random.Next(0, int.MaxValue)); } + _dataTable = new SimpleBinaryOpTest__DataTable<UInt32, UInt32, UInt32>(_data1, _data2, new UInt32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => Avx2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Avx2.Permute2x128( + Unsafe.Read<Vector256<UInt32>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector256<UInt32>>(_dataTable.inArray2Ptr), + 2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Avx2.Permute2x128( + Avx.LoadVector256((UInt32*)(_dataTable.inArray1Ptr)), + Avx.LoadVector256((UInt32*)(_dataTable.inArray2Ptr)), + 2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Avx2.Permute2x128( + Avx.LoadAlignedVector256((UInt32*)(_dataTable.inArray1Ptr)), + Avx.LoadAlignedVector256((UInt32*)(_dataTable.inArray2Ptr)), + 2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.Permute2x128), new Type[] { typeof(Vector256<UInt32>), typeof(Vector256<UInt32>), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector256<UInt32>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector256<UInt32>>(_dataTable.inArray2Ptr), + (byte)2 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<UInt32>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.Permute2x128), new Type[] { typeof(Vector256<UInt32>), typeof(Vector256<UInt32>), typeof(byte) }) + .Invoke(null, new object[] { + Avx.LoadVector256((UInt32*)(_dataTable.inArray1Ptr)), + Avx.LoadVector256((UInt32*)(_dataTable.inArray2Ptr)), + (byte)2 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<UInt32>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.Permute2x128), new Type[] { typeof(Vector256<UInt32>), typeof(Vector256<UInt32>), typeof(byte) }) + .Invoke(null, new object[] { + Avx.LoadAlignedVector256((UInt32*)(_dataTable.inArray1Ptr)), + Avx.LoadAlignedVector256((UInt32*)(_dataTable.inArray2Ptr)), + (byte)2 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<UInt32>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Avx2.Permute2x128( + _clsVar1, + _clsVar2, + 2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read<Vector256<UInt32>>(_dataTable.inArray1Ptr); + var right = Unsafe.Read<Vector256<UInt32>>(_dataTable.inArray2Ptr); + var result = Avx2.Permute2x128(left, right, 2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Avx.LoadVector256((UInt32*)(_dataTable.inArray1Ptr)); + var right = Avx.LoadVector256((UInt32*)(_dataTable.inArray2Ptr)); + var result = Avx2.Permute2x128(left, right, 2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Avx.LoadAlignedVector256((UInt32*)(_dataTable.inArray1Ptr)); + var right = Avx.LoadAlignedVector256((UInt32*)(_dataTable.inArray2Ptr)); + var result = Avx2.Permute2x128(left, right, 2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__Permute2x128UInt322(); + var result = Avx2.Permute2x128(test._fld1, test._fld2, 2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Avx2.Permute2x128(_fld1, _fld2, 2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector256<UInt32> left, Vector256<UInt32> right, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As<UInt32, byte>(ref inArray1[0]), left); + Unsafe.WriteUnaligned(ref Unsafe.As<UInt32, byte>(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt32, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), (uint)Unsafe.SizeOf<Vector256<UInt32>>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt32, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), (uint)Unsafe.SizeOf<Vector256<UInt32>>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt32, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), (uint)Unsafe.SizeOf<Vector256<UInt32>>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt32, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), (uint)Unsafe.SizeOf<Vector256<UInt32>>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt32[] left, UInt32[] right, UInt32[] result, [CallerMemberName] string method = "") + { + if (result[0] != right[0]) + { + Succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (i > 3 ? (result[i] != left[i - 4]) : (result[i] != right[i])) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Avx2)}.{nameof(Avx2.Permute2x128)}<UInt32>(Vector256<UInt32>.2, Vector256<UInt32>): {method} failed:"); + Console.WriteLine($" left: ({string.Join(", ", left)})"); + Console.WriteLine($" right: ({string.Join(", ", right)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx2/Permute2x128.UInt64.2.cs b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/Permute2x128.UInt64.2.cs new file mode 100644 index 0000000000..15a271b266 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/Permute2x128.UInt64.2.cs @@ -0,0 +1,337 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\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.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.X86; + +namespace JIT.HardwareIntrinsics.X86 +{ + public static partial class Program + { + private static void Permute2x128UInt642() + { + var test = new SimpleBinaryOpTest__Permute2x128UInt642(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + + // Validates basic functionality works, using LoadAligned + test.RunBasicScenario_LoadAligned(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + + // Validates calling via reflection works, using LoadAligned + test.RunReflectionScenario_LoadAligned(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + + // Validates passing a local works, using LoadAligned + test.RunLclVarScenario_LoadAligned(); + } + + // Validates passing the field of a local works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + 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 SimpleBinaryOpTest__Permute2x128UInt642 + { + private static readonly int LargestVectorSize = 32; + + private static readonly int Op1ElementCount = Unsafe.SizeOf<Vector256<UInt64>>() / sizeof(UInt64); + private static readonly int Op2ElementCount = Unsafe.SizeOf<Vector256<UInt64>>() / sizeof(UInt64); + private static readonly int RetElementCount = Unsafe.SizeOf<Vector256<UInt64>>() / sizeof(UInt64); + + private static UInt64[] _data1 = new UInt64[Op1ElementCount]; + private static UInt64[] _data2 = new UInt64[Op2ElementCount]; + + private static Vector256<UInt64> _clsVar1; + private static Vector256<UInt64> _clsVar2; + + private Vector256<UInt64> _fld1; + private Vector256<UInt64> _fld2; + + private SimpleBinaryOpTest__DataTable<UInt64, UInt64, UInt64> _dataTable; + + static SimpleBinaryOpTest__Permute2x128UInt642() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (ulong)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<UInt64>, byte>(ref _clsVar1), ref Unsafe.As<UInt64, byte>(ref _data1[0]), (uint)Unsafe.SizeOf<Vector256<UInt64>>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (ulong)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<UInt64>, byte>(ref _clsVar2), ref Unsafe.As<UInt64, byte>(ref _data2[0]), (uint)Unsafe.SizeOf<Vector256<UInt64>>()); + } + + public SimpleBinaryOpTest__Permute2x128UInt642() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (ulong)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<UInt64>, byte>(ref _fld1), ref Unsafe.As<UInt64, byte>(ref _data1[0]), (uint)Unsafe.SizeOf<Vector256<UInt64>>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (ulong)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<UInt64>, byte>(ref _fld2), ref Unsafe.As<UInt64, byte>(ref _data2[0]), (uint)Unsafe.SizeOf<Vector256<UInt64>>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (ulong)(random.Next(0, int.MaxValue)); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (ulong)(random.Next(0, int.MaxValue)); } + _dataTable = new SimpleBinaryOpTest__DataTable<UInt64, UInt64, UInt64>(_data1, _data2, new UInt64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => Avx2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Avx2.Permute2x128( + Unsafe.Read<Vector256<UInt64>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector256<UInt64>>(_dataTable.inArray2Ptr), + 2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Avx2.Permute2x128( + Avx.LoadVector256((UInt64*)(_dataTable.inArray1Ptr)), + Avx.LoadVector256((UInt64*)(_dataTable.inArray2Ptr)), + 2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Avx2.Permute2x128( + Avx.LoadAlignedVector256((UInt64*)(_dataTable.inArray1Ptr)), + Avx.LoadAlignedVector256((UInt64*)(_dataTable.inArray2Ptr)), + 2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.Permute2x128), new Type[] { typeof(Vector256<UInt64>), typeof(Vector256<UInt64>), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector256<UInt64>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector256<UInt64>>(_dataTable.inArray2Ptr), + (byte)2 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<UInt64>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.Permute2x128), new Type[] { typeof(Vector256<UInt64>), typeof(Vector256<UInt64>), typeof(byte) }) + .Invoke(null, new object[] { + Avx.LoadVector256((UInt64*)(_dataTable.inArray1Ptr)), + Avx.LoadVector256((UInt64*)(_dataTable.inArray2Ptr)), + (byte)2 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<UInt64>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.Permute2x128), new Type[] { typeof(Vector256<UInt64>), typeof(Vector256<UInt64>), typeof(byte) }) + .Invoke(null, new object[] { + Avx.LoadAlignedVector256((UInt64*)(_dataTable.inArray1Ptr)), + Avx.LoadAlignedVector256((UInt64*)(_dataTable.inArray2Ptr)), + (byte)2 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<UInt64>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Avx2.Permute2x128( + _clsVar1, + _clsVar2, + 2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read<Vector256<UInt64>>(_dataTable.inArray1Ptr); + var right = Unsafe.Read<Vector256<UInt64>>(_dataTable.inArray2Ptr); + var result = Avx2.Permute2x128(left, right, 2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Avx.LoadVector256((UInt64*)(_dataTable.inArray1Ptr)); + var right = Avx.LoadVector256((UInt64*)(_dataTable.inArray2Ptr)); + var result = Avx2.Permute2x128(left, right, 2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Avx.LoadAlignedVector256((UInt64*)(_dataTable.inArray1Ptr)); + var right = Avx.LoadAlignedVector256((UInt64*)(_dataTable.inArray2Ptr)); + var result = Avx2.Permute2x128(left, right, 2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__Permute2x128UInt642(); + var result = Avx2.Permute2x128(test._fld1, test._fld2, 2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Avx2.Permute2x128(_fld1, _fld2, 2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector256<UInt64> left, Vector256<UInt64> right, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray1 = new UInt64[Op1ElementCount]; + UInt64[] inArray2 = new UInt64[Op2ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As<UInt64, byte>(ref inArray1[0]), left); + Unsafe.WriteUnaligned(ref Unsafe.As<UInt64, byte>(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt64, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), (uint)Unsafe.SizeOf<Vector256<UInt64>>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray1 = new UInt64[Op1ElementCount]; + UInt64[] inArray2 = new UInt64[Op2ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt64, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), (uint)Unsafe.SizeOf<Vector256<UInt64>>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt64, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), (uint)Unsafe.SizeOf<Vector256<UInt64>>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt64, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), (uint)Unsafe.SizeOf<Vector256<UInt64>>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt64[] left, UInt64[] right, UInt64[] result, [CallerMemberName] string method = "") + { + if (result[0] != right[0]) + { + Succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (i > 1 ? (result[i] != left[i - 2]) : (result[i] != right[i])) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Avx2)}.{nameof(Avx2.Permute2x128)}<UInt64>(Vector256<UInt64>.2, Vector256<UInt64>): {method} failed:"); + Console.WriteLine($" left: ({string.Join(", ", left)})"); + Console.WriteLine($" right: ({string.Join(", ", right)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx2/Program.Avx2.cs b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/Program.Avx2.cs index 65d93f357d..5b38d5eb08 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Avx2/Program.Avx2.cs +++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/Program.Avx2.cs @@ -104,6 +104,18 @@ namespace JIT.HardwareIntrinsics.X86 ["InsertVector128.UInt32.1.Load"] = InsertVector128UInt321Load, ["InsertVector128.Int64.1.Load"] = InsertVector128Int641Load, ["InsertVector128.UInt64.1.Load"] = InsertVector128UInt641Load, + ["Max.Int16"] = MaxInt16, + ["Max.Byte"] = MaxByte, + ["Max.Int32"] = MaxInt32, + ["Max.SByte"] = MaxSByte, + ["Max.UInt16"] = MaxUInt16, + ["Max.UInt32"] = MaxUInt32, + ["Min.Int16"] = MinInt16, + ["Min.Byte"] = MinByte, + ["Min.Int32"] = MinInt32, + ["Min.SByte"] = MinSByte, + ["Min.UInt16"] = MinUInt16, + ["Min.UInt32"] = MinUInt32, ["Or.Byte"] = OrByte, ["Or.Int16"] = OrInt16, ["Or.Int32"] = OrInt32, @@ -112,6 +124,10 @@ namespace JIT.HardwareIntrinsics.X86 ["Or.UInt16"] = OrUInt16, ["Or.UInt32"] = OrUInt32, ["Or.UInt64"] = OrUInt64, + ["Permute2x128.Int32.2"] = Permute2x128Int322, + ["Permute2x128.UInt32.2"] = Permute2x128UInt322, + ["Permute2x128.Int64.2"] = Permute2x128Int642, + ["Permute2x128.UInt64.2"] = Permute2x128UInt642, ["ShiftLeftLogical.Int16.1"] = ShiftLeftLogicalInt161, ["ShiftLeftLogical.UInt16.1"] = ShiftLeftLogicalUInt161, ["ShiftLeftLogical.Int32.1"] = ShiftLeftLogicalInt321, diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx2/Program.ConvertToVector256.cs b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/Program.ConvertToVector256.cs new file mode 100644 index 0000000000..0848ebb1be --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/Program.ConvertToVector256.cs @@ -0,0 +1,30 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; + +namespace JIT.HardwareIntrinsics.X86 +{ + public static partial class Program + { + static Program() + { + TestList = new Dictionary<string, Action>() { + ["ConvertToVector256UInt16.Byte"] = ConvertToVector256UInt16Byte, + ["ConvertToVector256Int16.SByte"] = ConvertToVector256Int16SByte, + ["ConvertToVector256UInt32.Byte"] = ConvertToVector256UInt32Byte, + ["ConvertToVector256Int32.Int16"] = ConvertToVector256Int32Int16, + ["ConvertToVector256Int32.SByte"] = ConvertToVector256Int32SByte, + ["ConvertToVector256UInt32.UInt16"] = ConvertToVector256UInt32UInt16, + ["ConvertToVector256UInt64.Byte"] = ConvertToVector256UInt64Byte, + ["ConvertToVector256Int64.Int16"] = ConvertToVector256Int64Int16, + ["ConvertToVector256Int64.Int32"] = ConvertToVector256Int64Int32, + ["ConvertToVector256Int64.SByte"] = ConvertToVector256Int64SByte, + ["ConvertToVector256UInt64.UInt16"] = ConvertToVector256UInt64UInt16, + ["ConvertToVector256UInt64.UInt32"] = ConvertToVector256UInt64UInt32, + }; + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Shared/GenerateTests.csx b/tests/src/JIT/HardwareIntrinsics/X86/Shared/GenerateTests.csx index a52a09503c..6a5c8abf64 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Shared/GenerateTests.csx +++ b/tests/src/JIT/HardwareIntrinsics/X86/Shared/GenerateTests.csx @@ -505,6 +505,8 @@ private static readonly (string templateFileName, Dictionary<string, string> tem ("ImmUnOpTest.template", new Dictionary<string, string> { ["Isa"] = "Avx", ["LoadIsa"] = "Avx", ["Method"] = "Permute", ["RetVectorType"] = "Vector256", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector256", ["Op1BaseType"] = "Double", ["Imm"] = "1", ["LargestVectorSize"] = "32", ["NextValueOp1"] = "(double)(random.NextDouble())", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(result[0]) != BitConverter.DoubleToInt64Bits(firstOp[1])", ["ValidateRemainingResults"] = "BitConverter.DoubleToInt64Bits(result[2]) != BitConverter.DoubleToInt64Bits(firstOp[2]) || BitConverter.DoubleToInt64Bits(result[2]) != BitConverter.DoubleToInt64Bits(firstOp[2])"}), ("ImmUnOpTest.template", new Dictionary<string, string> { ["Isa"] = "Avx", ["LoadIsa"] = "Sse", ["Method"] = "Permute", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["Imm"] = "2", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "(float)(random.NextDouble())", ["ValidateFirstResult"] = "BitConverter.SingleToInt32Bits(result[0]) != BitConverter.SingleToInt32Bits(firstOp[2])", ["ValidateRemainingResults"] = "BitConverter.SingleToInt32Bits(result[1]) != BitConverter.SingleToInt32Bits(firstOp[0]) || BitConverter.SingleToInt32Bits(result[2]) != BitConverter.SingleToInt32Bits(firstOp[0])"}), ("ImmUnOpTest.template", new Dictionary<string, string> { ["Isa"] = "Avx", ["LoadIsa"] = "Sse2",["Method"] = "Permute", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["Imm"] = "2", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "(double)(random.NextDouble())", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(result[0]) != BitConverter.DoubleToInt64Bits(firstOp[0])", ["ValidateRemainingResults"] = "BitConverter.DoubleToInt64Bits(result[1]) != BitConverter.DoubleToInt64Bits(firstOp[1])"}), + ("SimpleBinOpTest.template", new Dictionary<string, string> { ["Isa"] = "Avx", ["LoadIsa"] = "Avx", ["Method"] = "PermuteVar", ["RetVectorType"] = "Vector256", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector256", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector256", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "32", ["NextValueOp1"] = "(float)(random.NextDouble())", ["NextValueOp2"] = "BitConverter.Int32BitsToSingle(1)", ["ValidateFirstResult"] = "BitConverter.SingleToInt32Bits(left[1]) != BitConverter.SingleToInt32Bits(result[0])", ["ValidateRemainingResults"] = "i > 3 ? (BitConverter.SingleToInt32Bits(left[5]) != BitConverter.SingleToInt32Bits(result[i])) : (BitConverter.SingleToInt32Bits(left[1]) != BitConverter.SingleToInt32Bits(result[i]))"}), + ("SimpleBinOpTest.template", new Dictionary<string, string> { ["Isa"] = "Avx", ["LoadIsa"] = "Avx", ["Method"] = "PermuteVar", ["RetVectorType"] = "Vector256", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector256", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector256", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "32", ["NextValueOp1"] = "(double)(random.NextDouble())", ["NextValueOp2"] = "BitConverter.Int64BitsToDouble(1)", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(left[0]) != BitConverter.DoubleToInt64Bits(result[0])", ["ValidateRemainingResults"] = "i > 1 ? (BitConverter.DoubleToInt64Bits(left[2]) != BitConverter.DoubleToInt64Bits(result[i])) : (BitConverter.DoubleToInt64Bits(left[0]) != BitConverter.DoubleToInt64Bits(result[i]))"}), ("SimpleUnOpTest.template", new Dictionary<string, string> { ["Isa"] = "Avx", ["LoadIsa"] = "Avx", ["Method"] = "RoundCurrentDirection", ["RetVectorType"] = "Vector256", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector256", ["Op1BaseType"] = "Double", ["LargestVectorSize"] = "32", ["NextValueOp1"] = "(double)(random.NextDouble())", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(result[0]) != BitConverter.DoubleToInt64Bits(Math.Round(firstOp[0]))", ["ValidateRemainingResults"] = "BitConverter.DoubleToInt64Bits(result[i]) != BitConverter.DoubleToInt64Bits(Math.Round(firstOp[i]))"}), ("SimpleUnOpTest.template", new Dictionary<string, string> { ["Isa"] = "Avx", ["LoadIsa"] = "Avx", ["Method"] = "RoundCurrentDirection", ["RetVectorType"] = "Vector256", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector256", ["Op1BaseType"] = "Single", ["LargestVectorSize"] = "32", ["NextValueOp1"] = "(float)(random.NextDouble())", ["ValidateFirstResult"] = "BitConverter.SingleToInt32Bits(result[0]) != BitConverter.SingleToInt32Bits(MathF.Round(firstOp[0]))", ["ValidateRemainingResults"] = "BitConverter.SingleToInt32Bits(result[i]) != BitConverter.SingleToInt32Bits(MathF.Round(firstOp[i]))"}), ("SimpleUnOpTest.template", new Dictionary<string, string> { ["Isa"] = "Avx", ["LoadIsa"] = "Avx", ["Method"] = "RoundToNearestInteger", ["RetVectorType"] = "Vector256", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector256", ["Op1BaseType"] = "Double", ["LargestVectorSize"] = "32", ["NextValueOp1"] = "(double)(random.NextDouble())", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(result[0]) != BitConverter.DoubleToInt64Bits(Math.Round(firstOp[0], MidpointRounding.AwayFromZero))", ["ValidateRemainingResults"] = "BitConverter.DoubleToInt64Bits(result[i]) != BitConverter.DoubleToInt64Bits(Math.Round(firstOp[i], MidpointRounding.AwayFromZero))"}), @@ -641,6 +643,18 @@ private static readonly (string templateFileName, Dictionary<string, string> tem ("InsertLoadTest.template", new Dictionary<string, string> { ["Isa"] = "Avx2", ["LoadIsa"] = "Avx", ["Method"] = "InsertVector128", ["RetVectorType"] = "Vector256", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector256", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt32", ["Imm"] = "1", ["LargestVectorSize"] = "32", ["NextValueOp1"] = "(uint)(random.Next(0, int.MaxValue))", ["NextValueOp2"] = "(uint)(random.Next(0,int.MaxValue))", ["ValidateFirstResult"] = "result[0] != left[0]", ["ValidateRemainingResults"] = "(i > 3 ? result[i] != right[i - 4] : result[i] != left[i])"}), ("InsertLoadTest.template", new Dictionary<string, string> { ["Isa"] = "Avx2", ["LoadIsa"] = "Avx", ["Method"] = "InsertVector128", ["RetVectorType"] = "Vector256", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector256", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int64", ["Imm"] = "1", ["LargestVectorSize"] = "32", ["NextValueOp1"] = "(long)(random.Next(0, int.MaxValue))", ["NextValueOp2"] = "(long)(random.Next(0,int.MaxValue))", ["ValidateFirstResult"] = "result[0] != left[0]", ["ValidateRemainingResults"] = "(i > 1 ? result[i] != right[i - 2] : result[i] != left[i])"}), ("InsertLoadTest.template", new Dictionary<string, string> { ["Isa"] = "Avx2", ["LoadIsa"] = "Avx", ["Method"] = "InsertVector128", ["RetVectorType"] = "Vector256", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector256", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt64", ["Imm"] = "1", ["LargestVectorSize"] = "32", ["NextValueOp1"] = "(ulong)(random.Next(0, int.MaxValue))", ["NextValueOp2"] = "(ulong)(random.Next(0,int.MaxValue))", ["ValidateFirstResult"] = "result[0] != left[0]", ["ValidateRemainingResults"] = "(i > 1 ? result[i] != right[i - 2] : result[i] != left[i])"}), + ("SimpleBinOpTest.template", new Dictionary<string, string> { ["Isa"] = "Avx2", ["LoadIsa"] = "Avx", ["Method"] = "Max", ["RetVectorType"] = "Vector256", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector256", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector256", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "32", ["NextValueOp1"] = "(short)(random.Next(short.MinValue, short.MaxValue))", ["NextValueOp2"] = "(short)(random.Next(short.MinValue, short.MaxValue))", ["ValidateFirstResult"] = "result[0] != Math.Max(left[0], right[0])", ["ValidateRemainingResults"] = "result[i] != Math.Max(left[i], right[i])"}), + ("SimpleBinOpTest.template", new Dictionary<string, string> { ["Isa"] = "Avx2", ["LoadIsa"] = "Avx", ["Method"] = "Max", ["RetVectorType"] = "Vector256", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector256", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector256", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "32", ["NextValueOp1"] = "(byte)(random.Next(byte.MinValue, byte.MaxValue))", ["NextValueOp2"] = "(byte)(random.Next(byte.MinValue, byte.MaxValue))", ["ValidateFirstResult"] = "result[0] != Math.Max(left[0], right[0])", ["ValidateRemainingResults"] = "result[i] != Math.Max(left[i], right[i])"}), + ("SimpleBinOpTest.template", new Dictionary<string, string> { ["Isa"] = "Avx2", ["LoadIsa"] = "Avx", ["Method"] = "Max", ["RetVectorType"] = "Vector256", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector256", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector256", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "32", ["NextValueOp1"] = "(int)(random.Next(int.MinValue, int.MaxValue))", ["NextValueOp2"] = "(int)(random.Next(int.MinValue, int.MaxValue))", ["ValidateFirstResult"] = "result[0] != Math.Max(left[0], right[0])", ["ValidateRemainingResults"] = "result[i] != Math.Max(left[i], right[i])"}), + ("SimpleBinOpTest.template", new Dictionary<string, string> { ["Isa"] = "Avx2", ["LoadIsa"] = "Avx", ["Method"] = "Max", ["RetVectorType"] = "Vector256", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector256", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector256", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "32", ["NextValueOp1"] = "(sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue))", ["NextValueOp2"] = "(sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue))", ["ValidateFirstResult"] = "result[0] != Math.Max(left[0], right[0])", ["ValidateRemainingResults"] = "result[i] != Math.Max(left[i], right[i])"}), + ("SimpleBinOpTest.template", new Dictionary<string, string> { ["Isa"] = "Avx2", ["LoadIsa"] = "Avx", ["Method"] = "Max", ["RetVectorType"] = "Vector256", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector256", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector256", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "32", ["NextValueOp1"] = "(ushort)(random.Next(0, ushort.MaxValue))", ["NextValueOp2"] = "(ushort)(random.Next(0, ushort.MaxValue))", ["ValidateFirstResult"] = "result[0] != Math.Max(left[0], right[0])", ["ValidateRemainingResults"] = "result[i] != Math.Max(left[i], right[i])"}), + ("SimpleBinOpTest.template", new Dictionary<string, string> { ["Isa"] = "Avx2", ["LoadIsa"] = "Avx", ["Method"] = "Max", ["RetVectorType"] = "Vector256", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector256", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector256", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "32", ["NextValueOp1"] = "(uint)(random.Next(0, int.MaxValue))", ["NextValueOp2"] = "(uint)(random.Next(0, int.MaxValue))", ["ValidateFirstResult"] = "result[0] != Math.Max(left[0], right[0])", ["ValidateRemainingResults"] = "result[i] != Math.Max(left[i], right[i])"}), + ("SimpleBinOpTest.template", new Dictionary<string, string> { ["Isa"] = "Avx2", ["LoadIsa"] = "Avx", ["Method"] = "Min", ["RetVectorType"] = "Vector256", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector256", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector256", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "32", ["NextValueOp1"] = "(short)(random.Next(short.MinValue, short.MaxValue))", ["NextValueOp2"] = "(short)(random.Next(short.MinValue, short.MaxValue))", ["ValidateFirstResult"] = "result[0] != Math.Min(left[0], right[0])", ["ValidateRemainingResults"] = "result[i] != Math.Min(left[i], right[i])"}), + ("SimpleBinOpTest.template", new Dictionary<string, string> { ["Isa"] = "Avx2", ["LoadIsa"] = "Avx", ["Method"] = "Min", ["RetVectorType"] = "Vector256", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector256", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector256", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "32", ["NextValueOp1"] = "(byte)(random.Next(byte.MinValue, byte.MaxValue))", ["NextValueOp2"] = "(byte)(random.Next(byte.MinValue, byte.MaxValue))", ["ValidateFirstResult"] = "result[0] != Math.Min(left[0], right[0])", ["ValidateRemainingResults"] = "result[i] != Math.Min(left[i], right[i])"}), + ("SimpleBinOpTest.template", new Dictionary<string, string> { ["Isa"] = "Avx2", ["LoadIsa"] = "Avx", ["Method"] = "Min", ["RetVectorType"] = "Vector256", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector256", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector256", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "32", ["NextValueOp1"] = "(int)(random.Next(int.MinValue, int.MaxValue))", ["NextValueOp2"] = "(int)(random.Next(int.MinValue, int.MaxValue))", ["ValidateFirstResult"] = "result[0] != Math.Min(left[0], right[0])", ["ValidateRemainingResults"] = "result[i] != Math.Min(left[i], right[i])"}), + ("SimpleBinOpTest.template", new Dictionary<string, string> { ["Isa"] = "Avx2", ["LoadIsa"] = "Avx", ["Method"] = "Min", ["RetVectorType"] = "Vector256", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector256", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector256", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "32", ["NextValueOp1"] = "(sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue))", ["NextValueOp2"] = "(sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue))", ["ValidateFirstResult"] = "result[0] != Math.Min(left[0], right[0])", ["ValidateRemainingResults"] = "result[i] != Math.Min(left[i], right[i])"}), + ("SimpleBinOpTest.template", new Dictionary<string, string> { ["Isa"] = "Avx2", ["LoadIsa"] = "Avx", ["Method"] = "Min", ["RetVectorType"] = "Vector256", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector256", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector256", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "32", ["NextValueOp1"] = "(ushort)(random.Next(0, ushort.MaxValue))", ["NextValueOp2"] = "(ushort)(random.Next(0, ushort.MaxValue))", ["ValidateFirstResult"] = "result[0] != Math.Min(left[0], right[0])", ["ValidateRemainingResults"] = "result[i] != Math.Min(left[i], right[i])"}), + ("SimpleBinOpTest.template", new Dictionary<string, string> { ["Isa"] = "Avx2", ["LoadIsa"] = "Avx", ["Method"] = "Min", ["RetVectorType"] = "Vector256", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector256", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector256", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "32", ["NextValueOp1"] = "(uint)(random.Next(0, int.MaxValue))", ["NextValueOp2"] = "(uint)(random.Next(0, int.MaxValue))", ["ValidateFirstResult"] = "result[0] != Math.Min(left[0], right[0])", ["ValidateRemainingResults"] = "result[i] != Math.Min(left[i], right[i])"}), ("SimpleBinOpTest.template", new Dictionary<string, string> { ["Isa"] = "Avx2", ["LoadIsa"] = "Avx", ["Method"] = "Or", ["RetVectorType"] = "Vector256", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector256", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector256", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "32", ["NextValueOp1"] = "(byte)(random.Next(0, byte.MaxValue))", ["NextValueOp2"] = "(byte)(random.Next(0, byte.MaxValue))", ["ValidateFirstResult"] = "(byte)(left[0] | right[0]) != result[0]", ["ValidateRemainingResults"] = "(byte)(left[i] | right[i]) != result[i]"}), ("SimpleBinOpTest.template", new Dictionary<string, string> { ["Isa"] = "Avx2", ["LoadIsa"] = "Avx", ["Method"] = "Or", ["RetVectorType"] = "Vector256", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector256", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector256", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "32", ["NextValueOp1"] = "(short)(random.Next(short.MinValue, short.MaxValue))", ["NextValueOp2"] = "(short)(random.Next(short.MinValue, short.MaxValue))", ["ValidateFirstResult"] = "(short)(left[0] | right[0]) != result[0]", ["ValidateRemainingResults"] = "(short)(left[i] | right[i]) != result[i]"}), ("SimpleBinOpTest.template", new Dictionary<string, string> { ["Isa"] = "Avx2", ["LoadIsa"] = "Avx", ["Method"] = "Or", ["RetVectorType"] = "Vector256", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector256", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector256", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "32", ["NextValueOp1"] = "(int)(random.Next(int.MinValue, int.MaxValue))", ["NextValueOp2"] = "(int)(random.Next(int.MinValue, int.MaxValue))", ["ValidateFirstResult"] = "(int)(left[0] | right[0]) != result[0]", ["ValidateRemainingResults"] = "(int)(left[i] | right[i]) != result[i]"}), @@ -649,6 +663,10 @@ private static readonly (string templateFileName, Dictionary<string, string> tem ("SimpleBinOpTest.template", new Dictionary<string, string> { ["Isa"] = "Avx2", ["LoadIsa"] = "Avx", ["Method"] = "Or", ["RetVectorType"] = "Vector256", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector256", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector256", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "32", ["NextValueOp1"] = "(ushort)(random.Next(0, ushort.MaxValue))", ["NextValueOp2"] = "(ushort)(random.Next(0, ushort.MaxValue))", ["ValidateFirstResult"] = "(ushort)(left[0] | right[0]) != result[0]", ["ValidateRemainingResults"] = "(ushort)(left[i] | right[i]) != result[i]"}), ("SimpleBinOpTest.template", new Dictionary<string, string> { ["Isa"] = "Avx2", ["LoadIsa"] = "Avx", ["Method"] = "Or", ["RetVectorType"] = "Vector256", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector256", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector256", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "32", ["NextValueOp1"] = "(uint)(random.Next(0, int.MaxValue))", ["NextValueOp2"] = "(uint)(random.Next(0, int.MaxValue))", ["ValidateFirstResult"] = "(uint)(left[0] | right[0]) != result[0]", ["ValidateRemainingResults"] = "(uint)(left[i] | right[i]) != result[i]"}), ("SimpleBinOpTest.template", new Dictionary<string, string> { ["Isa"] = "Avx2", ["LoadIsa"] = "Avx", ["Method"] = "Or", ["RetVectorType"] = "Vector256", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector256", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector256", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "32", ["NextValueOp1"] = "(ulong)(random.Next(0, int.MaxValue))", ["NextValueOp2"] = "(ulong)(random.Next(0, int.MaxValue))", ["ValidateFirstResult"] = "(ulong)(left[0] | right[0]) != result[0]", ["ValidateRemainingResults"] = "(ulong)(left[i] | right[i]) != result[i]"}), + ("ImmBinOpTest.template", new Dictionary<string, string> { ["Isa"] = "Avx2", ["LoadIsa"] = "Avx", ["Method"] = "Permute2x128", ["RetVectorType"] = "Vector256", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector256", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector256", ["Op2BaseType"] = "Int32", ["Imm"] = "2", ["LargestVectorSize"] = "32", ["NextValueOp1"] = "(int)(random.Next(0, int.MaxValue))", ["NextValueOp2"] = "(int)(random.Next(0, int.MaxValue))", ["ValidateFirstResult"] = "result[0] != right[0]", ["ValidateRemainingResults"] = "i > 3 ? (result[i] != left[i - 4]) : (result[i] != right[i])"}), + ("ImmBinOpTest.template", new Dictionary<string, string> { ["Isa"] = "Avx2", ["LoadIsa"] = "Avx", ["Method"] = "Permute2x128", ["RetVectorType"] = "Vector256", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector256", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector256", ["Op2BaseType"] = "UInt32", ["Imm"] = "2", ["LargestVectorSize"] = "32", ["NextValueOp1"] = "(uint)(random.Next(0, int.MaxValue))", ["NextValueOp2"] = "(uint)(random.Next(0, int.MaxValue))", ["ValidateFirstResult"] = "result[0] != right[0]", ["ValidateRemainingResults"] = "i > 3 ? (result[i] != left[i - 4]) : (result[i] != right[i])"}), + ("ImmBinOpTest.template", new Dictionary<string, string> { ["Isa"] = "Avx2", ["LoadIsa"] = "Avx", ["Method"] = "Permute2x128", ["RetVectorType"] = "Vector256", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector256", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector256", ["Op2BaseType"] = "Int64", ["Imm"] = "2", ["LargestVectorSize"] = "32", ["NextValueOp1"] = "(long)(random.Next(0, int.MaxValue))", ["NextValueOp2"] = "(long)(random.Next(0, int.MaxValue))", ["ValidateFirstResult"] = "result[0] != right[0]", ["ValidateRemainingResults"] = "i > 1 ? (result[i] != left[i - 2]) : (result[i] != right[i])"}), + ("ImmBinOpTest.template", new Dictionary<string, string> { ["Isa"] = "Avx2", ["LoadIsa"] = "Avx", ["Method"] = "Permute2x128", ["RetVectorType"] = "Vector256", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector256", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector256", ["Op2BaseType"] = "UInt64", ["Imm"] = "2", ["LargestVectorSize"] = "32", ["NextValueOp1"] = "(ulong)(random.Next(0, int.MaxValue))", ["NextValueOp2"] = "(ulong)(random.Next(0, int.MaxValue))", ["ValidateFirstResult"] = "result[0] != right[0]", ["ValidateRemainingResults"] = "i > 1 ? (result[i] != left[i - 2]) : (result[i] != right[i])"}), ("ImmUnOpTest.template", new Dictionary<string, string> { ["Isa"] = "Avx2", ["LoadIsa"] = "Avx", ["Method"] = "ShiftLeftLogical", ["RetVectorType"] = "Vector256", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector256", ["Op1BaseType"] = "Int16", ["Imm"] = "1", ["LargestVectorSize"] = "32", ["NextValueOp1"] = "(short)(random.Next(0, short.MaxValue))", ["ValidateFirstResult"] = "(short)(firstOp[0] << 1) != result[0]", ["ValidateRemainingResults"] = "(short)(firstOp[i] << 1) != result[i]"}), ("ImmUnOpTest.template", new Dictionary<string, string> { ["Isa"] = "Avx2", ["LoadIsa"] = "Avx", ["Method"] = "ShiftLeftLogical", ["RetVectorType"] = "Vector256", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector256", ["Op1BaseType"] = "UInt16", ["Imm"] = "1", ["LargestVectorSize"] = "32", ["NextValueOp1"] = "(ushort)(random.Next(0, ushort.MaxValue))", ["ValidateFirstResult"] = "(ushort)(firstOp[0] << 1) != result[0]", ["ValidateRemainingResults"] = "(ushort)(firstOp[i] << 1) != result[i]"}), ("ImmUnOpTest.template", new Dictionary<string, string> { ["Isa"] = "Avx2", ["LoadIsa"] = "Avx", ["Method"] = "ShiftLeftLogical", ["RetVectorType"] = "Vector256", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector256", ["Op1BaseType"] = "Int32", ["Imm"] = "1", ["LargestVectorSize"] = "32", ["NextValueOp1"] = "(int)(random.Next(0, int.MaxValue))", ["ValidateFirstResult"] = "(int)(firstOp[0] << 1) != result[0]", ["ValidateRemainingResults"] = "(int)(firstOp[i] << 1) != result[i]"}), |