From f85b8a1cdf84795fc6a1a420461763990637e9d8 Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Sun, 25 Feb 2018 09:27:18 -0800 Subject: [PATCH 1/3] Adding partial support for the SSE41 hardware intrinsics --- src/jit/emitxarch.cpp | 4 ++ src/jit/hwintrinsiccodegenxarch.cpp | 97 ++++++++++++++++++++++++++++- src/jit/hwintrinsiclistxarch.h | 45 +++++++++++-- src/jit/hwintrinsicxarch.cpp | 39 +++++++++++- src/jit/instrsxarch.h | 16 ++++- src/jit/lsraxarch.cpp | 7 +++ 6 files changed, 200 insertions(+), 8 deletions(-) diff --git a/src/jit/emitxarch.cpp b/src/jit/emitxarch.cpp index 7e47ccfb7dd8..2753c2dc8192 100644 --- a/src/jit/emitxarch.cpp +++ b/src/jit/emitxarch.cpp @@ -87,6 +87,8 @@ bool emitter::IsDstDstSrcAVXInstruction(instruction ins) case INS_andnps: case INS_andpd: case INS_andps: + case INS_blendpd: + case INS_blendps: case INS_cmppd: case INS_cmpps: case INS_cmpsd: @@ -114,6 +116,7 @@ bool emitter::IsDstDstSrcAVXInstruction(instruction ins) case INS_minss: case INS_movhlps: case INS_movlhps: + case INS_mpsadbw: case INS_mulpd: case INS_mulps: case INS_mulsd: @@ -137,6 +140,7 @@ bool emitter::IsDstDstSrcAVXInstruction(instruction ins) case INS_pandn: case INS_pavgb: case INS_pavgw: + case INS_pblendw: case INS_pcmpeqb: case INS_pcmpeqd: case INS_pcmpeqq: diff --git a/src/jit/hwintrinsiccodegenxarch.cpp b/src/jit/hwintrinsiccodegenxarch.cpp index dbc2e35fcb16..2c6a184b3a0e 100644 --- a/src/jit/hwintrinsiccodegenxarch.cpp +++ b/src/jit/hwintrinsiccodegenxarch.cpp @@ -91,6 +91,10 @@ void CodeGen::genHWIntrinsic(GenTreeHWIntrinsic* node) { emit->emitIns_SIMD_R_R_R(ins, simdSize, targetReg, op1Reg, op1Reg); } + else if ((ival != -1) && varTypeIsFloating(baseType)) + { + emit->emitIns_R_R_I(ins, simdSize, targetReg, op1Reg, ival); + } else { emit->emitIns_R_R(ins, simdSize, targetReg, op1Reg); @@ -1027,7 +1031,98 @@ void CodeGen::genSSE2Intrinsic(GenTreeHWIntrinsic* node) // void CodeGen::genSSE41Intrinsic(GenTreeHWIntrinsic* node) { - NYI("Implement SSE41 intrinsic code generation"); + NamedIntrinsic intrinsicID = node->gtHWIntrinsicId; + GenTree* op1 = node->gtGetOp1(); + GenTree* op2 = node->gtGetOp2(); + GenTree* op3 = nullptr; + GenTree* op4 = nullptr; + regNumber targetReg = node->gtRegNum; + var_types targetType = node->TypeGet(); + var_types baseType = node->gtSIMDBaseType; + + regNumber op1Reg = REG_NA; + regNumber op2Reg = REG_NA; + regNumber op3Reg = REG_NA; + regNumber op4Reg = REG_NA; + emitter* emit = getEmitter(); + + if ((op1 != nullptr) && !op1->OperIsList()) + { + op1Reg = op1->gtRegNum; + genConsumeOperands(node); + } + + switch (intrinsicID) + { + case NI_SSE41_CeilingScalar: + case NI_SSE41_FloorScalar: + case NI_SSE41_RoundCurrentDirectionScalar: + case NI_SSE41_RoundToNearestIntegerScalar: + case NI_SSE41_RoundToNegativeInfinityScalar: + case NI_SSE41_RoundToPositiveInfinityScalar: + case NI_SSE41_RoundToZeroScalar: + { + assert((baseType == TYP_FLOAT) || (baseType == TYP_DOUBLE)); + instruction ins = Compiler::insOfHWIntrinsic(intrinsicID, node->gtSIMDBaseType); + + if (op2 == nullptr) + { + int ival = Compiler::ivalOfHWIntrinsic(intrinsicID); + emit->emitIns_SIMD_R_R_R_I(ins, emitTypeSize(TYP_SIMD16), targetReg, op1Reg, op1Reg, ival); + } + else + { + genHWIntrinsic_R_R_RM_I(node, ins); + } + break; + } + + case NI_SSE41_TestAllOnes: + { + regNumber tmpReg = node->GetSingleTempReg(); + assert(Compiler::insOfHWIntrinsic(intrinsicID, node->gtSIMDBaseType) == INS_ptest); + emit->emitIns_SIMD_R_R_R(INS_pcmpeqd, emitTypeSize(TYP_SIMD16), tmpReg, tmpReg, tmpReg); + emit->emitIns_R_R(INS_xor, EA_4BYTE, targetReg, targetReg); + emit->emitIns_R_R(INS_ptest, emitTypeSize(TYP_SIMD16), op1Reg, tmpReg); + emit->emitIns_R(INS_setb, EA_1BYTE, targetReg); + break; + } + + case NI_SSE41_TestAllZeros: + case NI_SSE41_TestZ: + { + assert(Compiler::insOfHWIntrinsic(intrinsicID, node->gtSIMDBaseType) == INS_ptest); + emit->emitIns_R_R(INS_xor, EA_4BYTE, targetReg, targetReg); + emit->emitIns_R_R(INS_ptest, emitTypeSize(TYP_SIMD16), op1Reg, op2->gtRegNum); + emit->emitIns_R(INS_sete, EA_1BYTE, targetReg); + break; + } + + case NI_SSE41_TestC: + { + assert(Compiler::insOfHWIntrinsic(intrinsicID, node->gtSIMDBaseType) == INS_ptest); + emit->emitIns_R_R(INS_xor, EA_4BYTE, targetReg, targetReg); + emit->emitIns_R_R(INS_ptest, emitTypeSize(TYP_SIMD16), op1Reg, op2->gtRegNum); + emit->emitIns_R(INS_setb, EA_1BYTE, targetReg); + break; + } + + case NI_SSE41_TestMixOnesZeros: + case NI_SSE41_TestNotZAndNotC: + { + assert(Compiler::insOfHWIntrinsic(intrinsicID, node->gtSIMDBaseType) == INS_ptest); + emit->emitIns_R_R(INS_xor, EA_4BYTE, targetReg, targetReg); + emit->emitIns_R_R(INS_ptest, emitTypeSize(TYP_SIMD16), op1Reg, op2->gtRegNum); + emit->emitIns_R(INS_seta, EA_1BYTE, targetReg); + break; + } + + default: + unreached(); + break; + } + + genProduceReg(node); } //------------------------------------------------------------------------ diff --git a/src/jit/hwintrinsiclistxarch.h b/src/jit/hwintrinsiclistxarch.h index 0c28863f1710..be9d0311360b 100644 --- a/src/jit/hwintrinsiclistxarch.h +++ b/src/jit/hwintrinsiclistxarch.h @@ -261,12 +261,47 @@ HARDWARE_INTRINSIC(SSSE3_MultiplyHighRoundScale, "MultiplyHi HARDWARE_INTRINSIC(SSSE3_Shuffle, "Shuffle", SSSE3, -1, 16, 2, {INS_pshufb, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) HARDWARE_INTRINSIC(SSSE3_Sign, "Sign", SSSE3, -1, 16, 2, {INS_psignb, INS_invalid, INS_psignw, INS_invalid, INS_psignd, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +// ************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************ +// Intrinsic ID Function name ISA ival SIMD size NumArg instructions Category Flags +// {TYP_BYTE, TYP_UBYTE, TYP_SHORT, TYP_USHORT, TYP_INT, TYP_UINT, TYP_LONG, TYP_ULONG, TYP_FLOAT, TYP_DOUBLE} +// ************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************ // SSE41 Intrinsics -HARDWARE_INTRINSIC(SSE41_IsSupported, "get_IsSupported", SSE41, -1, 0, 0, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_IsSupportedProperty, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(SSE41_BlendVariable, "BlendVariable", SSE41, -1, 16, 3, {INS_pblendvb, INS_pblendvb, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_blendvps, INS_blendvpd}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(SSE41_CompareEqual, "CompareEqual", SSE41, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_pcmpeqq, INS_pcmpeqq, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_Commutative) -HARDWARE_INTRINSIC(SSE41_LoadAlignedVector128NonTemporal, "LoadAlignedVector128NonTemporal", SSE41, -1, 16, 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_NoFlag) -HARDWARE_INTRINSIC(SSE41_Multiply, "Multiply", SSE41, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_pmuldq, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_Commutative) +HARDWARE_INTRINSIC(SSE41_IsSupported, "get_IsSupported", SSE41, -1, 0, 0, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_IsSupportedProperty, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(SSE41_Blend, "Blend", SSE41, -1, 16, 3, {INS_invalid, INS_invalid, INS_pblendw, INS_pblendw, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_blendps, INS_blendpd}, HW_Category_IMM, HW_Flag_FullRangeIMM) +HARDWARE_INTRINSIC(SSE41_BlendVariable, "BlendVariable", SSE41, -1, 16, 3, {INS_pblendvb, INS_pblendvb, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_blendvps, INS_blendvpd}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(SSE41_Ceiling, "Ceiling", SSE41, 10, 16, 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_NoFlag) +HARDWARE_INTRINSIC(SSE41_CeilingScalar, "CeilingScalar", SSE41, 10, 16, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_roundss, INS_roundsd}, HW_Category_Special, HW_Flag_CopyUpperBits) +HARDWARE_INTRINSIC(SSE41_CompareEqual, "CompareEqual", SSE41, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_pcmpeqq, INS_pcmpeqq, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_Commutative) +HARDWARE_INTRINSIC(SSE41_ConvertToVector128Int16, "ConvertToVector128Int16", SSE41, -1, 16, 1, {INS_pmovsxbw, INS_pmovzxbw, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_BaseTypeFromArg) +HARDWARE_INTRINSIC(SSE41_ConvertToVector128Int32, "ConvertToVector128Int32", SSE41, -1, 16, 1, {INS_pmovsxbd, INS_pmovzxbd, INS_pmovsxwd, INS_pmovzxwd, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_BaseTypeFromArg) +HARDWARE_INTRINSIC(SSE41_ConvertToVector128Int64, "ConvertToVector128Int64", SSE41, -1, 16, 1, {INS_pmovsxbq, INS_pmovzxbq, INS_pmovsxwq, INS_pmovzxwq, INS_pmovsxdq, INS_pmovzxdq, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_BaseTypeFromArg) +HARDWARE_INTRINSIC(SSE41_DotProduct, "DotProduct", SSE41, -1, 16, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_dpps, INS_dppd}, HW_Category_IMM, HW_Flag_FullRangeIMM) +HARDWARE_INTRINSIC(SSE41_Floor, "Floor", SSE41, 9, 16, 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_NoFlag) +HARDWARE_INTRINSIC(SSE41_FloorScalar, "FloorScalar", SSE41, 9, 16, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_roundss, INS_roundsd}, HW_Category_Special, HW_Flag_CopyUpperBits) +HARDWARE_INTRINSIC(SSE41_LoadAlignedVector128NonTemporal, "LoadAlignedVector128NonTemporal", SSE41, -1, 16, 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_NoFlag) +HARDWARE_INTRINSIC(SSE41_Max, "Max", SSE41, -1, 16, 2, {INS_pmaxsb, INS_invalid, INS_invalid, INS_pmaxuw, INS_pmaxsd, INS_pmaxud, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(SSE41_Min, "Min", SSE41, -1, 16, 2, {INS_pminsb, INS_invalid, INS_invalid, INS_pminuw, INS_pminsd, INS_pminud, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(SSE41_MinHorizontal, "MinHorizontal", SSE41, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_phminposuw, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(SSE41_MultipleSumAbsoluteDifferences, "MultipleSumAbsoluteDifferences", SSE41, -1, 16, 3, {INS_invalid, INS_invalid, INS_invalid, INS_mpsadbw, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_FullRangeIMM) +HARDWARE_INTRINSIC(SSE41_Multiply, "Multiply", SSE41, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_pmuldq, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_Commutative) +HARDWARE_INTRINSIC(SSE41_MultiplyLow, "MultiplyLow", SSE41, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_pmulld, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(SSE41_PackUnsignedSaturate, "PackUnsignedSaturate", SSE41, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_packusdw, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(SSE41_RoundCurrentDirection, "RoundCurrentDirection", SSE41, 4, 16, 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_NoFlag) +HARDWARE_INTRINSIC(SSE41_RoundCurrentDirectionScalar, "RoundCurrentDirectionScalar", SSE41, 4, 16, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_roundss, INS_roundsd}, HW_Category_Special, HW_Flag_CopyUpperBits) +HARDWARE_INTRINSIC(SSE41_RoundToNearestInteger, "RoundToNearestInteger", SSE41, 8, 16, 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_NoFlag) +HARDWARE_INTRINSIC(SSE41_RoundToNearestIntegerScalar, "RoundToNearestIntegerScalar", SSE41, 8, 16, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_roundss, INS_roundsd}, HW_Category_Special, HW_Flag_CopyUpperBits) +HARDWARE_INTRINSIC(SSE41_RoundToNegativeInfinity, "RoundToNegativeInfinity", SSE41, 9, 16, 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_NoFlag) +HARDWARE_INTRINSIC(SSE41_RoundToNegativeInfinityScalar, "RoundToNegativeInfinityScalar", SSE41, 9, 16, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_roundss, INS_roundsd}, HW_Category_Special, HW_Flag_CopyUpperBits) +HARDWARE_INTRINSIC(SSE41_RoundToPositiveInfinity, "RoundToPositiveInfinity", SSE41, 10, 16, 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_NoFlag) +HARDWARE_INTRINSIC(SSE41_RoundToPositiveInfinityScalar, "RoundToPositiveInfinityScalar", SSE41, 10, 16, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_roundss, INS_roundsd}, HW_Category_Special, HW_Flag_CopyUpperBits) +HARDWARE_INTRINSIC(SSE41_RoundToZero, "RoundToZero", SSE41, 11, 16, 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_NoFlag) +HARDWARE_INTRINSIC(SSE41_RoundToZeroScalar, "RoundToZeroScalar", SSE41, 11, 16, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_roundss, INS_roundsd}, HW_Category_Special, HW_Flag_CopyUpperBits) +HARDWARE_INTRINSIC(SSE41_TestAllOnes, "TestAllOnes", SSE41, -1, 16, 1, {INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_MultiIns|HW_Flag_NoContainment) +HARDWARE_INTRINSIC(SSE41_TestAllZeros, "TestAllZeros", SSE41, -1, 16, 2, {INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_MultiIns|HW_Flag_NoContainment) +HARDWARE_INTRINSIC(SSE41_TestC, "TestC", SSE41, -1, 16, 2, {INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_MultiIns|HW_Flag_NoContainment) +HARDWARE_INTRINSIC(SSE41_TestMixOnesZeros, "TestMixOnesZeros", SSE41, -1, 16, 2, {INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_MultiIns|HW_Flag_NoContainment) +HARDWARE_INTRINSIC(SSE41_TestNotZAndNotC, "TestNotZAndNotC", SSE41, -1, 16, 2, {INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_MultiIns|HW_Flag_NoContainment) +HARDWARE_INTRINSIC(SSE41_TestZ, "TestZ", SSE41, -1, 16, 2, {INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_MultiIns|HW_Flag_NoContainment) // SSE42 Intrinsics HARDWARE_INTRINSIC(SSE42_IsSupported, "get_IsSupported", SSE42, -1, 0, 0, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_IsSupportedProperty, HW_Flag_NoFlag) diff --git a/src/jit/hwintrinsicxarch.cpp b/src/jit/hwintrinsicxarch.cpp index 4ab3bf828525..7aabb8abb465 100644 --- a/src/jit/hwintrinsicxarch.cpp +++ b/src/jit/hwintrinsicxarch.cpp @@ -1089,7 +1089,44 @@ GenTree* Compiler::impSSE41Intrinsic(NamedIntrinsic intrinsic, CORINFO_SIG_INFO* sig, bool mustExpand) { - return nullptr; + GenTree* retNode = nullptr; + GenTree* op1 = nullptr; + GenTree* op2 = nullptr; + GenTree* op3 = nullptr; + GenTree* op4 = nullptr; + int simdSize = simdSizeOfHWIntrinsic(intrinsic, sig); + + assert(simdSize == 16); + + switch (intrinsic) + { + case NI_SSE41_CeilingScalar: + case NI_SSE41_FloorScalar: + case NI_SSE41_RoundCurrentDirectionScalar: + case NI_SSE41_RoundToNearestIntegerScalar: + case NI_SSE41_RoundToNegativeInfinityScalar: + case NI_SSE41_RoundToPositiveInfinityScalar: + case NI_SSE41_RoundToZeroScalar: + { + assert((sig->numArgs == 1) || (sig->numArgs == 2)); + var_types baseType = getBaseTypeOfSIMDType(sig->retTypeSigClass); + assert((baseType == TYP_FLOAT) || (baseType == TYP_DOUBLE)); + + if (sig->numArgs == 2) + { + op2 = impSIMDPopStack(TYP_SIMD16); + } + + op1 = impSIMDPopStack(TYP_SIMD16); + retNode = gtNewSimdHWIntrinsicNode(TYP_SIMD16, op1, op2, intrinsic, baseType, simdSize); + break; + } + + default: + JITDUMP("Not implemented hardware intrinsic"); + break; + } + return retNode; } GenTree* Compiler::impSSE42Intrinsic(NamedIntrinsic intrinsic, diff --git a/src/jit/instrsxarch.h b/src/jit/instrsxarch.h index 3d314a699f63..ae8adffea68f 100644 --- a/src/jit/instrsxarch.h +++ b/src/jit/instrsxarch.h @@ -416,16 +416,28 @@ INST3( pmaxsd, "pmaxsd" , 0, IUM_WR, 0, 0, BAD_CODE, BAD_CODE, SS INST3( pmaxuw, "pmaxuw" , 0, IUM_WR, 0, 0, BAD_CODE, BAD_CODE, SSE38(0x3E)) // packed maximum 16-bit unsigned integers INST3( pmaxud, "pmaxud" , 0, IUM_WR, 0, 0, BAD_CODE, BAD_CODE, SSE38(0x3F)) // packed maximum 32-bit unsigned integers INST3( pmovsxbw, "pmovsxbw" , 0, IUM_WR, 0, 0, BAD_CODE, BAD_CODE, SSE38(0x20)) // Packed sign extend byte to short +INST3( pmovsxbd, "pmovsxbd" , 0, IUM_WR, 0, 0, BAD_CODE, BAD_CODE, SSE38(0x21)) // Packed sign extend byte to int +INST3( pmovsxbq, "pmovsxbq" , 0, IUM_WR, 0, 0, BAD_CODE, BAD_CODE, SSE38(0x22)) // Packed sign extend byte to long INST3( pmovsxwd, "pmovsxwd" , 0, IUM_WR, 0, 0, BAD_CODE, BAD_CODE, SSE38(0x23)) // Packed sign extend short to int +INST3( pmovsxwq, "pmovsxwq" , 0, IUM_WR, 0, 0, BAD_CODE, BAD_CODE, SSE38(0x24)) // Packed sign extend short to long INST3( pmovsxdq, "pmovsxdq" , 0, IUM_WR, 0, 0, BAD_CODE, BAD_CODE, SSE38(0x25)) // Packed sign extend int to long +INST3( pmovzxbw, "pmovzxbw" , 0, IUM_WR, 0, 0, BAD_CODE, BAD_CODE, SSE38(0x30)) // Packed zero extend byte to short +INST3( pmovzxbd, "pmovzxbd" , 0, IUM_WR, 0, 0, BAD_CODE, BAD_CODE, SSE38(0x31)) // Packed zero extend byte to intg +INST3( pmovzxbq, "pmovzxbq" , 0, IUM_WR, 0, 0, BAD_CODE, BAD_CODE, SSE38(0x32)) // Packed zero extend byte to lon +INST3( pmovzxwd, "pmovzxwd" , 0, IUM_WR, 0, 0, BAD_CODE, BAD_CODE, SSE38(0x33)) // Packed zero extend short to int +INST3( pmovzxwq, "pmovzxwq" , 0, IUM_WR, 0, 0, BAD_CODE, BAD_CODE, SSE38(0x34)) // Packed zero extend short to long +INST3( pmovzxdq, "pmovzxdq" , 0, IUM_WR, 0, 0, BAD_CODE, BAD_CODE, SSE38(0x35)) // Packed zero extend int to long INST3( packusdw, "packusdw" , 0, IUM_WR, 0, 0, BAD_CODE, BAD_CODE, SSE38(0x2B)) // Pack (narrow) int to unsigned short with saturation INST3( roundps, "roundps" , 0, IUM_WR, 0, 0, BAD_CODE, BAD_CODE, SSE3A(0x08)) // Round packed single precision floating-point values INST3( roundss, "roundss" , 0, IUM_WR, 0, 0, BAD_CODE, BAD_CODE, SSE3A(0x0A)) // Round scalar single precision floating-point values INST3( roundpd, "roundpd" , 0, IUM_WR, 0, 0, BAD_CODE, BAD_CODE, SSE3A(0x09)) // Round packed double precision floating-point values INST3( roundsd, "roundsd" , 0, IUM_WR, 0, 0, BAD_CODE, BAD_CODE, SSE3A(0x0B)) // Round scalar double precision floating-point values INST3( pmuldq, "pmuldq" , 0, IUM_WR, 0, 0, BAD_CODE, BAD_CODE, SSE38(0x28)) // packed multiply 32-bit signed integers and store 64-bit result +INST3( blendps, "blendps" , 0, IUM_WR, 0, 0, BAD_CODE, BAD_CODE, SSE3A(0x0C)) // Blend Packed Single Precision Floating-Point Values INST3( blendvps, "blendvps" , 0, IUM_WR, 0, 0, BAD_CODE, BAD_CODE, SSE38(0x14)) // Variable Blend Packed Singles +INST3( blendpd, "blendpd" , 0, IUM_WR, 0, 0, BAD_CODE, BAD_CODE, SSE3A(0x0D)) // Blend Packed Double Precision Floating-Point Values INST3( blendvpd, "blendvpd" , 0, IUM_WR, 0, 0, BAD_CODE, BAD_CODE, SSE38(0x15)) // Variable Blend Packed Doubles +INST3( pblendw, "pblendw" , 0, IUM_WR, 0, 0, BAD_CODE, BAD_CODE, SSE3A(0x0E)) // Blend Packed Words INST3( pblendvb, "pblendvb" , 0, IUM_WR, 0, 0, BAD_CODE, BAD_CODE, SSE38(0x10)) // Variable Blend Packed Bytes INST3( phaddw, "phaddw" , 0, IUM_WR, 0, 0, BAD_CODE, BAD_CODE, SSE38(0x01)) // Packed horizontal add of 16-bit integers INST3( phsubw, "phsubw" , 0, IUM_WR, 0, 0, BAD_CODE, BAD_CODE, SSE38(0x05)) // Packed horizontal subtract of 16-bit integers @@ -434,9 +446,11 @@ INST3( phaddsw, "phaddsw" , 0, IUM_WR, 0, 0, BAD_CODE, BAD_CODE, SS INST3( phsubsw, "phsubsw" , 0, IUM_WR, 0, 0, BAD_CODE, BAD_CODE, SSE38(0x07)) // Packed horizontal subtract of 16-bit integers with saturation INST3( lddqu, "lddqu" , 0, IUM_WR, 0, 0, BAD_CODE, BAD_CODE, SSEDBL(0xF0)) // Load Unaligned integer INST3( movntdqa, "movntdqa" , 0, IUM_WR, 0, 0, BAD_CODE, BAD_CODE, SSE38(0x2A)) // Load Double Quadword Non-Temporal Aligned Hint -INST3( movddup, "movddup" , 0, IUM_WR, 0, 0, BAD_CODE, BAD_CODE, SSEDBL(0x12)) // Replicate Double FP Values +INST3( movddup, "movddup" , 0, IUM_WR, 0, 0, BAD_CODE, BAD_CODE, SSEDBL(0x12)) // Replicate Double FP Values INST3( movsldup, "movsldup" , 0, IUM_WR, 0, 0, BAD_CODE, BAD_CODE, SSEFLT(0x12)) // Replicate even-indexed Single FP Values INST3( movshdup, "movshdup" , 0, IUM_WR, 0, 0, BAD_CODE, BAD_CODE, SSEFLT(0x16)) // Replicate odd-indexed Single FP Values +INST3( phminposuw, "phminposuw" , 0, IUM_WR, 0, 0, BAD_CODE, BAD_CODE, SSE38(0x41)) // Packed Horizontal Word Minimum +INST3( mpsadbw, "mpsadbw" , 0, IUM_WR, 0, 0, BAD_CODE, BAD_CODE, SSE3A(0x42)) // Compute Multiple Packed Sums of Absolute Difference INST3(LAST_SSE4_INSTRUCTION, "LAST_SSE4_INSTRUCTION", 0, IUM_WR, 0, 0, BAD_CODE, BAD_CODE, BAD_CODE) diff --git a/src/jit/lsraxarch.cpp b/src/jit/lsraxarch.cpp index 6ff82a78eed2..e5a74fdf8408 100644 --- a/src/jit/lsraxarch.cpp +++ b/src/jit/lsraxarch.cpp @@ -2344,6 +2344,13 @@ void LinearScan::BuildHWIntrinsic(GenTreeHWIntrinsic* intrinsicTree) } break; + case NI_SSE41_TestAllOnes: + { + info->internalFloatCount = 1; + info->setInternalCandidates(this, allSIMDRegs()); + break; + } + #ifdef _TARGET_X86_ case NI_SSE42_Crc32: { From 315f8e9e0f526de6d8d7bc4c685e918867ddeeaa Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Sun, 25 Feb 2018 09:28:36 -0800 Subject: [PATCH 2/3] Adding tests for the implemented SSE41 hardware intrinsics --- .../X86/Shared/BooleanBinOpTest.template | 306 +++++++++++++ .../X86/Shared/BooleanBinOpTest_DataTable.cs | 58 +++ .../X86/Shared/BooleanTwoCmpOpTest.template | 313 +++++++++++++ .../Shared/BooleanTwoCmpOpTest_DataTable.cs | 58 +++ .../X86/Shared/BooleanUnOpTest.template | 283 ++++++++++++ .../X86/Shared/BooleanUnOpTest_DataTable.cs | 50 +++ .../X86/Shared/GenerateTests.csx | 96 +++- .../X86/Shared/HorizontalBinOpTest.template | 8 +- .../JIT/HardwareIntrinsics/X86/Sse41/Blend.cs | 424 ++++++++++++++++++ .../X86/Sse41/BlendVariable.Byte.cs | 354 +++++++++++++++ .../X86/Sse41/BlendVariable.Double.cs | 354 +++++++++++++++ .../X86/Sse41/BlendVariable.SByte.cs | 354 +++++++++++++++ .../X86/Sse41/BlendVariable.Single.cs | 354 +++++++++++++++ .../X86/Sse41/Blend_r.csproj | 34 ++ .../X86/Sse41/Blend_ro.csproj | 34 ++ .../X86/Sse41/Ceiling.Double.cs | 306 +++++++++++++ .../X86/Sse41/Ceiling.Single.cs | 306 +++++++++++++ .../X86/Sse41/CeilingScalar.Double.cs | 330 ++++++++++++++ .../X86/Sse41/CeilingScalar.Single.cs | 330 ++++++++++++++ .../X86/Sse41/ConvertToVector128Int16.Byte.cs | 306 +++++++++++++ .../Sse41/ConvertToVector128Int16.SByte.cs | 306 +++++++++++++ .../X86/Sse41/ConvertToVector128Int32.Byte.cs | 306 +++++++++++++ .../Sse41/ConvertToVector128Int32.Int16.cs | 306 +++++++++++++ .../Sse41/ConvertToVector128Int32.SByte.cs | 306 +++++++++++++ .../Sse41/ConvertToVector128Int32.UInt16.cs | 306 +++++++++++++ .../X86/Sse41/ConvertToVector128Int64.Byte.cs | 306 +++++++++++++ .../Sse41/ConvertToVector128Int64.Int16.cs | 306 +++++++++++++ .../Sse41/ConvertToVector128Int64.Int32.cs | 306 +++++++++++++ .../Sse41/ConvertToVector128Int64.SByte.cs | 306 +++++++++++++ .../Sse41/ConvertToVector128Int64.UInt16.cs | 306 +++++++++++++ .../Sse41/ConvertToVector128Int64.UInt32.cs | 306 +++++++++++++ .../X86/Sse41/ConvertToVector128_r.csproj | 48 ++ .../X86/Sse41/ConvertToVector128_ro.csproj | 48 ++ .../X86/Sse41/DotProduct.cs | 225 ++++++++++ .../X86/Sse41/DotProduct_r.csproj | 34 ++ .../X86/Sse41/DotProduct_ro.csproj | 34 ++ .../X86/Sse41/Floor.Double.cs | 306 +++++++++++++ .../X86/Sse41/Floor.Single.cs | 306 +++++++++++++ .../X86/Sse41/FloorScalar.Double.cs | 330 ++++++++++++++ .../X86/Sse41/FloorScalar.Single.cs | 330 ++++++++++++++ .../HardwareIntrinsics/X86/Sse41/Max.Int32.cs | 330 ++++++++++++++ .../HardwareIntrinsics/X86/Sse41/Max.SByte.cs | 330 ++++++++++++++ .../X86/Sse41/Max.UInt16.cs | 330 ++++++++++++++ .../X86/Sse41/Max.UInt32.cs | 330 ++++++++++++++ .../HardwareIntrinsics/X86/Sse41/Min.Int32.cs | 330 ++++++++++++++ .../HardwareIntrinsics/X86/Sse41/Min.SByte.cs | 330 ++++++++++++++ .../X86/Sse41/Min.UInt16.cs | 330 ++++++++++++++ .../X86/Sse41/Min.UInt32.cs | 330 ++++++++++++++ .../X86/Sse41/MinHorizontal.cs | 318 +++++++++++++ .../X86/Sse41/MinHorizontal_r.csproj | 36 ++ .../X86/Sse41/MinHorizontal_ro.csproj | 36 ++ .../Sse41/MultipleSumAbsoluteDifferences.cs | 415 +++++++++++++++++ .../MultipleSumAbsoluteDifferences_r.csproj | 36 ++ .../MultipleSumAbsoluteDifferences_ro.csproj | 36 ++ .../X86/Sse41/MultiplyLow.Int32.cs | 330 ++++++++++++++ .../X86/Sse41/PackUnsignedSaturate.UInt16.cs | 336 ++++++++++++++ .../X86/Sse41/Program.ConvertToVector128.cs | 30 ++ .../X86/Sse41/Program.Sse41.cs | 90 ++++ .../X86/Sse41/RoundCurrentDirection.Double.cs | 306 +++++++++++++ .../X86/Sse41/RoundCurrentDirection.Single.cs | 306 +++++++++++++ .../RoundCurrentDirectionScalar.Double.cs | 330 ++++++++++++++ .../RoundCurrentDirectionScalar.Single.cs | 330 ++++++++++++++ .../X86/Sse41/RoundToNearestInteger.Double.cs | 306 +++++++++++++ .../X86/Sse41/RoundToNearestInteger.Single.cs | 306 +++++++++++++ .../RoundToNearestIntegerScalar.Double.cs | 330 ++++++++++++++ .../RoundToNearestIntegerScalar.Single.cs | 330 ++++++++++++++ .../Sse41/RoundToNegativeInfinity.Double.cs | 306 +++++++++++++ .../Sse41/RoundToNegativeInfinity.Single.cs | 306 +++++++++++++ .../RoundToNegativeInfinityScalar.Double.cs | 330 ++++++++++++++ .../RoundToNegativeInfinityScalar.Single.cs | 330 ++++++++++++++ .../Sse41/RoundToPositiveInfinity.Double.cs | 306 +++++++++++++ .../Sse41/RoundToPositiveInfinity.Single.cs | 306 +++++++++++++ .../RoundToPositiveInfinityScalar.Double.cs | 330 ++++++++++++++ .../RoundToPositiveInfinityScalar.Single.cs | 330 ++++++++++++++ .../X86/Sse41/RoundToZero.Double.cs | 306 +++++++++++++ .../X86/Sse41/RoundToZero.Single.cs | 306 +++++++++++++ .../X86/Sse41/RoundToZeroScalar.Double.cs | 330 ++++++++++++++ .../X86/Sse41/RoundToZeroScalar.Single.cs | 330 ++++++++++++++ .../X86/Sse41/Sse41_r.csproj | 99 +++- .../X86/Sse41/Sse41_ro.csproj | 99 +++- .../X86/Sse41/TestAllOnes.Byte.cs | 283 ++++++++++++ .../X86/Sse41/TestAllOnes.Int16.cs | 283 ++++++++++++ .../X86/Sse41/TestAllOnes.Int32.cs | 283 ++++++++++++ .../X86/Sse41/TestAllOnes.Int64.cs | 283 ++++++++++++ .../X86/Sse41/TestAllOnes.SByte.cs | 283 ++++++++++++ .../X86/Sse41/TestAllOnes.UInt16.cs | 283 ++++++++++++ .../X86/Sse41/TestAllOnes.UInt32.cs | 283 ++++++++++++ .../X86/Sse41/TestAllOnes.UInt64.cs | 283 ++++++++++++ .../X86/Sse41/TestAllZeros.Byte.cs | 306 +++++++++++++ .../X86/Sse41/TestAllZeros.Int16.cs | 306 +++++++++++++ .../X86/Sse41/TestAllZeros.Int32.cs | 306 +++++++++++++ .../X86/Sse41/TestAllZeros.Int64.cs | 306 +++++++++++++ .../X86/Sse41/TestAllZeros.SByte.cs | 306 +++++++++++++ .../X86/Sse41/TestAllZeros.UInt16.cs | 306 +++++++++++++ .../X86/Sse41/TestAllZeros.UInt32.cs | 306 +++++++++++++ .../X86/Sse41/TestAllZeros.UInt64.cs | 306 +++++++++++++ .../X86/Sse41/TestC.Byte.cs | 306 +++++++++++++ .../X86/Sse41/TestC.Int16.cs | 306 +++++++++++++ .../X86/Sse41/TestC.Int32.cs | 306 +++++++++++++ .../X86/Sse41/TestC.Int64.cs | 306 +++++++++++++ .../X86/Sse41/TestC.SByte.cs | 306 +++++++++++++ .../X86/Sse41/TestC.UInt16.cs | 306 +++++++++++++ .../X86/Sse41/TestC.UInt32.cs | 306 +++++++++++++ .../X86/Sse41/TestC.UInt64.cs | 306 +++++++++++++ .../X86/Sse41/TestMixOnesZeros.Byte.cs | 313 +++++++++++++ .../X86/Sse41/TestMixOnesZeros.Int16.cs | 313 +++++++++++++ .../X86/Sse41/TestMixOnesZeros.Int32.cs | 313 +++++++++++++ .../X86/Sse41/TestMixOnesZeros.Int64.cs | 313 +++++++++++++ .../X86/Sse41/TestMixOnesZeros.SByte.cs | 313 +++++++++++++ .../X86/Sse41/TestMixOnesZeros.UInt16.cs | 313 +++++++++++++ .../X86/Sse41/TestMixOnesZeros.UInt32.cs | 313 +++++++++++++ .../X86/Sse41/TestMixOnesZeros.UInt64.cs | 313 +++++++++++++ .../X86/Sse41/TestNotZAndNotC.Byte.cs | 313 +++++++++++++ .../X86/Sse41/TestNotZAndNotC.Int16.cs | 313 +++++++++++++ .../X86/Sse41/TestNotZAndNotC.Int32.cs | 313 +++++++++++++ .../X86/Sse41/TestNotZAndNotC.Int64.cs | 313 +++++++++++++ .../X86/Sse41/TestNotZAndNotC.SByte.cs | 313 +++++++++++++ .../X86/Sse41/TestNotZAndNotC.UInt16.cs | 313 +++++++++++++ .../X86/Sse41/TestNotZAndNotC.UInt32.cs | 313 +++++++++++++ .../X86/Sse41/TestNotZAndNotC.UInt64.cs | 313 +++++++++++++ .../X86/Sse41/TestZ.Byte.cs | 306 +++++++++++++ .../X86/Sse41/TestZ.Int16.cs | 306 +++++++++++++ .../X86/Sse41/TestZ.Int32.cs | 306 +++++++++++++ .../X86/Sse41/TestZ.Int64.cs | 306 +++++++++++++ .../X86/Sse41/TestZ.SByte.cs | 306 +++++++++++++ .../X86/Sse41/TestZ.UInt16.cs | 306 +++++++++++++ .../X86/Sse41/TestZ.UInt32.cs | 306 +++++++++++++ .../X86/Sse41/TestZ.UInt64.cs | 306 +++++++++++++ 128 files changed, 35151 insertions(+), 11 deletions(-) create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Shared/BooleanBinOpTest.template create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Shared/BooleanBinOpTest_DataTable.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Shared/BooleanTwoCmpOpTest.template create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Shared/BooleanTwoCmpOpTest_DataTable.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Shared/BooleanUnOpTest.template create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Shared/BooleanUnOpTest_DataTable.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/Blend.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/BlendVariable.Byte.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/BlendVariable.Double.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/BlendVariable.SByte.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/BlendVariable.Single.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/Blend_r.csproj create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/Blend_ro.csproj create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/Ceiling.Double.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/Ceiling.Single.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/CeilingScalar.Double.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/CeilingScalar.Single.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/ConvertToVector128Int16.Byte.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/ConvertToVector128Int16.SByte.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/ConvertToVector128Int32.Byte.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/ConvertToVector128Int32.Int16.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/ConvertToVector128Int32.SByte.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/ConvertToVector128Int32.UInt16.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/ConvertToVector128Int64.Byte.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/ConvertToVector128Int64.Int16.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/ConvertToVector128Int64.Int32.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/ConvertToVector128Int64.SByte.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/ConvertToVector128Int64.UInt16.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/ConvertToVector128Int64.UInt32.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/ConvertToVector128_r.csproj create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/ConvertToVector128_ro.csproj create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/DotProduct.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/DotProduct_r.csproj create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/DotProduct_ro.csproj create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/Floor.Double.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/Floor.Single.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/FloorScalar.Double.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/FloorScalar.Single.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/Max.Int32.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/Max.SByte.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/Max.UInt16.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/Max.UInt32.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/Min.Int32.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/Min.SByte.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/Min.UInt16.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/Min.UInt32.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/MinHorizontal.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/MinHorizontal_r.csproj create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/MinHorizontal_ro.csproj create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/MultipleSumAbsoluteDifferences.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/MultipleSumAbsoluteDifferences_r.csproj create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/MultipleSumAbsoluteDifferences_ro.csproj create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/MultiplyLow.Int32.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/PackUnsignedSaturate.UInt16.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/Program.ConvertToVector128.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/RoundCurrentDirection.Double.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/RoundCurrentDirection.Single.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/RoundCurrentDirectionScalar.Double.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/RoundCurrentDirectionScalar.Single.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/RoundToNearestInteger.Double.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/RoundToNearestInteger.Single.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/RoundToNearestIntegerScalar.Double.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/RoundToNearestIntegerScalar.Single.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/RoundToNegativeInfinity.Double.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/RoundToNegativeInfinity.Single.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/RoundToNegativeInfinityScalar.Double.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/RoundToNegativeInfinityScalar.Single.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/RoundToPositiveInfinity.Double.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/RoundToPositiveInfinity.Single.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/RoundToPositiveInfinityScalar.Double.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/RoundToPositiveInfinityScalar.Single.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/RoundToZero.Double.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/RoundToZero.Single.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/RoundToZeroScalar.Double.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/RoundToZeroScalar.Single.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestAllOnes.Byte.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestAllOnes.Int16.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestAllOnes.Int32.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestAllOnes.Int64.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestAllOnes.SByte.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestAllOnes.UInt16.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestAllOnes.UInt32.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestAllOnes.UInt64.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestAllZeros.Byte.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestAllZeros.Int16.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestAllZeros.Int32.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestAllZeros.Int64.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestAllZeros.SByte.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestAllZeros.UInt16.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestAllZeros.UInt32.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestAllZeros.UInt64.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestC.Byte.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestC.Int16.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestC.Int32.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestC.Int64.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestC.SByte.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestC.UInt16.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestC.UInt32.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestC.UInt64.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestMixOnesZeros.Byte.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestMixOnesZeros.Int16.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestMixOnesZeros.Int32.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestMixOnesZeros.Int64.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestMixOnesZeros.SByte.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestMixOnesZeros.UInt16.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestMixOnesZeros.UInt32.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestMixOnesZeros.UInt64.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestNotZAndNotC.Byte.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestNotZAndNotC.Int16.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestNotZAndNotC.Int32.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestNotZAndNotC.Int64.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestNotZAndNotC.SByte.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestNotZAndNotC.UInt16.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestNotZAndNotC.UInt32.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestNotZAndNotC.UInt64.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestZ.Byte.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestZ.Int16.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestZ.Int32.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestZ.Int64.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestZ.SByte.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestZ.UInt16.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestZ.UInt32.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestZ.UInt64.cs diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Shared/BooleanBinOpTest.template b/tests/src/JIT/HardwareIntrinsics/X86/Shared/BooleanBinOpTest.template new file mode 100644 index 000000000000..4eab3a107dc5 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Shared/BooleanBinOpTest.template @@ -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 {2}{4}() + {{ + var test = new BooleanBinaryOpTest__{2}{4}(); + + if (test.IsSupported) + {{ + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if ({1}.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 ({1}.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 ({1}.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 BooleanBinaryOpTest__{2}{4} + {{ + private const int VectorSize = {9}; + + private const int Op1ElementCount = VectorSize / sizeof({6}); + private const int Op2ElementCount = VectorSize / sizeof({8}); + + private static {6}[] _data1 = new {6}[Op1ElementCount]; + private static {8}[] _data2 = new {8}[Op2ElementCount]; + + private static {5}<{6}> _clsVar1; + private static {7}<{8}> _clsVar2; + + private {5}<{6}> _fld1; + private {7}<{8}> _fld2; + + private BooleanBinaryOpTest__DataTable<{6}, {8}> _dataTable; + + static BooleanBinaryOpTest__{2}{4}() + {{ + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) {{ _data1[i] = {10}; }} + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{5}<{6}>, byte>(ref _clsVar1), ref Unsafe.As<{6}, byte>(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) {{ _data2[i] = {11}; }} + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{7}<{8}>, byte>(ref _clsVar2), ref Unsafe.As<{8}, byte>(ref _data2[0]), VectorSize); + }} + + public BooleanBinaryOpTest__{2}{4}() + {{ + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) {{ _data1[i] = {10}; }} + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{5}<{6}>, byte>(ref _fld1), ref Unsafe.As<{6}, byte>(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) {{ _data2[i] = {11}; }} + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{7}<{8}>, byte>(ref _fld2), ref Unsafe.As<{8}, byte>(ref _data2[0]), VectorSize); + + for (var i = 0; i < Op1ElementCount; i++) {{ _data1[i] = {10}; }} + for (var i = 0; i < Op2ElementCount; i++) {{ _data2[i] = {11}; }} + _dataTable = new BooleanBinaryOpTest__DataTable<{6}, {8}>(_data1, _data2, VectorSize); + }} + + public bool IsSupported => {0}.IsSupported; + + public bool Succeeded {{ get; set; }} + + public void RunBasicScenario_UnsafeRead() + {{ + var result = {0}.{2}( + Unsafe.Read<{5}<{6}>>(_dataTable.inArray1Ptr), + Unsafe.Read<{7}<{8}>>(_dataTable.inArray2Ptr) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + }} + + public void RunBasicScenario_Load() + {{ + var result = {0}.{2}( + {1}.Load{5}(({6}*)(_dataTable.inArray1Ptr)), + {1}.Load{7}(({8}*)(_dataTable.inArray2Ptr)) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + }} + + public void RunBasicScenario_LoadAligned() + {{ + var result = {0}.{2}( + {1}.LoadAligned{5}(({6}*)(_dataTable.inArray1Ptr)), + {1}.LoadAligned{7}(({8}*)(_dataTable.inArray2Ptr)) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + }} + + public void RunReflectionScenario_UnsafeRead() + {{ + var result = typeof({0}).GetMethod(nameof({0}.{2}), new Type[] {{ typeof({5}<{6}>), typeof({7}<{8}>) }}) + .Invoke(null, new object[] {{ + Unsafe.Read<{5}<{6}>>(_dataTable.inArray1Ptr), + Unsafe.Read<{7}<{8}>>(_dataTable.inArray2Ptr) + }}); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + }} + + public void RunReflectionScenario_Load() + {{ + var result = typeof({0}).GetMethod(nameof({0}.{2}), new Type[] {{ typeof({5}<{6}>), typeof({7}<{8}>) }}) + .Invoke(null, new object[] {{ + {1}.Load{5}(({6}*)(_dataTable.inArray1Ptr)), + {1}.Load{7}(({8}*)(_dataTable.inArray2Ptr)) + }}); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + }} + + public void RunReflectionScenario_LoadAligned() + {{ + var result = typeof({0}).GetMethod(nameof({0}.{2}), new Type[] {{ typeof({5}<{6}>), typeof({7}<{8}>) }}) + .Invoke(null, new object[] {{ + {1}.LoadAligned{5}(({6}*)(_dataTable.inArray1Ptr)), + {1}.LoadAligned{7}(({8}*)(_dataTable.inArray2Ptr)) + }}); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + }} + + public void RunClsVarScenario() + {{ + var result = {0}.{2}( + _clsVar1, + _clsVar2 + ); + + ValidateResult(_clsVar1, _clsVar2, result); + }} + + public void RunLclVarScenario_UnsafeRead() + {{ + var left = Unsafe.Read<{5}<{6}>>(_dataTable.inArray1Ptr); + var right = Unsafe.Read<{7}<{8}>>(_dataTable.inArray2Ptr); + var result = {0}.{2}(left, right); + + ValidateResult(left, right, result); + }} + + public void RunLclVarScenario_Load() + {{ + var left = {1}.Load{5}(({6}*)(_dataTable.inArray1Ptr)); + var right = {1}.Load{7}(({8}*)(_dataTable.inArray2Ptr)); + var result = {0}.{2}(left, right); + + ValidateResult(left, right, result); + }} + + public void RunLclVarScenario_LoadAligned() + {{ + var left = {1}.LoadAligned{5}(({6}*)(_dataTable.inArray1Ptr)); + var right = {1}.LoadAligned{7}(({8}*)(_dataTable.inArray2Ptr)); + var result = {0}.{2}(left, right); + + ValidateResult(left, right, result); + }} + + public void RunLclFldScenario() + {{ + var test = new BooleanBinaryOpTest__{2}{4}(); + var result = {0}.{2}(test._fld1, test._fld2); + + ValidateResult(test._fld1, test._fld2, result); + }} + + public void RunFldScenario() + {{ + var result = {0}.{2}(_fld1, _fld2); + + ValidateResult(_fld1, _fld2, result); + }} + + public void RunUnsupportedScenario() + {{ + Succeeded = false; + + try + {{ + RunBasicScenario_UnsafeRead(); + }} + catch (PlatformNotSupportedException) + {{ + Succeeded = true; + }} + }} + + private void ValidateResult({5}<{6}> left, {7}<{8}> right, bool result, [CallerMemberName] string method = "") + {{ + {6}[] inArray1 = new {6}[Op1ElementCount]; + {8}[] inArray2 = new {8}[Op2ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + + ValidateResult(inArray1, inArray2, result, method); + }} + + private void ValidateResult(void* left, void* right, bool result, [CallerMemberName] string method = "") + {{ + {6}[] inArray1 = new {6}[Op1ElementCount]; + {8}[] inArray2 = new {8}[Op2ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{6}, byte>(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{8}, byte>(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + + ValidateResult(inArray1, inArray2, result, method); + }} + + private void ValidateResult({6}[] left, {8}[] right, bool result, [CallerMemberName] string method = "") + {{ + var expectedResult = true; + + for (var i = 0; i < Op1ElementCount; i++) + {{ + expectedResult &= ({12}); + }} + + if (expectedResult != result) + {{ + Succeeded = false; + + Console.WriteLine($"{{nameof({0})}}.{{nameof({0}.{2})}}<{4}>({5}<{6}>, {7}<{8}>): {{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/Shared/BooleanBinOpTest_DataTable.cs b/tests/src/JIT/HardwareIntrinsics/X86/Shared/BooleanBinOpTest_DataTable.cs new file mode 100644 index 000000000000..36b94502b259 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Shared/BooleanBinOpTest_DataTable.cs @@ -0,0 +1,58 @@ +// 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; +using System.Runtime.Intrinsics.X86; + +namespace JIT.HardwareIntrinsics.X86 +{ + public unsafe struct BooleanBinaryOpTest__DataTable : IDisposable + where TOp1 : struct + where TOp2 : struct + { + private byte[] inArray1; + private byte[] inArray2; + + private GCHandle inHandle1; + private GCHandle inHandle2; + + private byte simdSize; + + public BooleanBinaryOpTest__DataTable(TOp1[] inArray1, TOp2[] inArray2, int simdSize) + { + this.inArray1 = new byte[simdSize * 2]; + this.inArray2 = new byte[simdSize * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + + this.simdSize = unchecked((byte)(simdSize)); + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), this.simdSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), this.simdSize); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), simdSize); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), simdSize); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + } + + private static unsafe void* Align(byte* buffer, byte expectedAlignment) + { + // Compute how bad the misalignment is, which is at most (expectedAlignment - 1). + // Then subtract that from the expectedAlignment and add it to the original address + // to compute the aligned address. + + var misalignment = expectedAlignment - ((ulong)(buffer) % expectedAlignment); + return (void*)(buffer + misalignment); + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Shared/BooleanTwoCmpOpTest.template b/tests/src/JIT/HardwareIntrinsics/X86/Shared/BooleanTwoCmpOpTest.template new file mode 100644 index 000000000000..3d816c0a0a7d --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Shared/BooleanTwoCmpOpTest.template @@ -0,0 +1,313 @@ +// 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 {2}{4}() + {{ + var test = new BooleanTwoComparisonOpTest__{2}{4}(); + + if (test.IsSupported) + {{ + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if ({1}.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 ({1}.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 ({1}.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 BooleanTwoComparisonOpTest__{2}{4} + {{ + private const int VectorSize = {9}; + + private const int Op1ElementCount = VectorSize / sizeof({6}); + private const int Op2ElementCount = VectorSize / sizeof({8}); + + private static {6}[] _data1 = new {6}[Op1ElementCount]; + private static {8}[] _data2 = new {8}[Op2ElementCount]; + + private static {5}<{6}> _clsVar1; + private static {7}<{8}> _clsVar2; + + private {5}<{6}> _fld1; + private {7}<{8}> _fld2; + + private BooleanTwoComparisonOpTest__DataTable<{6}, {8}> _dataTable; + + static BooleanTwoComparisonOpTest__{2}{4}() + {{ + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) {{ _data1[i] = {10}; }} + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{5}<{6}>, byte>(ref _clsVar1), ref Unsafe.As<{6}, byte>(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) {{ _data2[i] = {11}; }} + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{7}<{8}>, byte>(ref _clsVar2), ref Unsafe.As<{8}, byte>(ref _data2[0]), VectorSize); + }} + + public BooleanTwoComparisonOpTest__{2}{4}() + {{ + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) {{ _data1[i] = {10}; }} + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{5}<{6}>, byte>(ref _fld1), ref Unsafe.As<{6}, byte>(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) {{ _data2[i] = {11}; }} + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{7}<{8}>, byte>(ref _fld2), ref Unsafe.As<{8}, byte>(ref _data2[0]), VectorSize); + + for (var i = 0; i < Op1ElementCount; i++) {{ _data1[i] = {10}; }} + for (var i = 0; i < Op2ElementCount; i++) {{ _data2[i] = {11}; }} + _dataTable = new BooleanTwoComparisonOpTest__DataTable<{6}, {8}>(_data1, _data2, VectorSize); + }} + + public bool IsSupported => {0}.IsSupported; + + public bool Succeeded {{ get; set; }} + + public void RunBasicScenario_UnsafeRead() + {{ + var result = {0}.{2}( + Unsafe.Read<{5}<{6}>>(_dataTable.inArray1Ptr), + Unsafe.Read<{7}<{8}>>(_dataTable.inArray2Ptr) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + }} + + public void RunBasicScenario_Load() + {{ + var result = {0}.{2}( + {1}.Load{5}(({6}*)(_dataTable.inArray1Ptr)), + {1}.Load{7}(({8}*)(_dataTable.inArray2Ptr)) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + }} + + public void RunBasicScenario_LoadAligned() + {{ + var result = {0}.{2}( + {1}.LoadAligned{5}(({6}*)(_dataTable.inArray1Ptr)), + {1}.LoadAligned{7}(({8}*)(_dataTable.inArray2Ptr)) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + }} + + public void RunReflectionScenario_UnsafeRead() + {{ + var result = typeof({0}).GetMethod(nameof({0}.{2}), new Type[] {{ typeof({5}<{6}>), typeof({7}<{8}>) }}) + .Invoke(null, new object[] {{ + Unsafe.Read<{5}<{6}>>(_dataTable.inArray1Ptr), + Unsafe.Read<{7}<{8}>>(_dataTable.inArray2Ptr) + }}); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + }} + + public void RunReflectionScenario_Load() + {{ + var result = typeof({0}).GetMethod(nameof({0}.{2}), new Type[] {{ typeof({5}<{6}>), typeof({7}<{8}>) }}) + .Invoke(null, new object[] {{ + {1}.Load{5}(({6}*)(_dataTable.inArray1Ptr)), + {1}.Load{7}(({8}*)(_dataTable.inArray2Ptr)) + }}); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + }} + + public void RunReflectionScenario_LoadAligned() + {{ + var result = typeof({0}).GetMethod(nameof({0}.{2}), new Type[] {{ typeof({5}<{6}>), typeof({7}<{8}>) }}) + .Invoke(null, new object[] {{ + {1}.LoadAligned{5}(({6}*)(_dataTable.inArray1Ptr)), + {1}.LoadAligned{7}(({8}*)(_dataTable.inArray2Ptr)) + }}); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + }} + + public void RunClsVarScenario() + {{ + var result = {0}.{2}( + _clsVar1, + _clsVar2 + ); + + ValidateResult(_clsVar1, _clsVar2, result); + }} + + public void RunLclVarScenario_UnsafeRead() + {{ + var left = Unsafe.Read<{5}<{6}>>(_dataTable.inArray1Ptr); + var right = Unsafe.Read<{7}<{8}>>(_dataTable.inArray2Ptr); + var result = {0}.{2}(left, right); + + ValidateResult(left, right, result); + }} + + public void RunLclVarScenario_Load() + {{ + var left = {1}.Load{5}(({6}*)(_dataTable.inArray1Ptr)); + var right = {1}.Load{7}(({8}*)(_dataTable.inArray2Ptr)); + var result = {0}.{2}(left, right); + + ValidateResult(left, right, result); + }} + + public void RunLclVarScenario_LoadAligned() + {{ + var left = {1}.LoadAligned{5}(({6}*)(_dataTable.inArray1Ptr)); + var right = {1}.LoadAligned{7}(({8}*)(_dataTable.inArray2Ptr)); + var result = {0}.{2}(left, right); + + ValidateResult(left, right, result); + }} + + public void RunLclFldScenario() + {{ + var test = new BooleanTwoComparisonOpTest__{2}{4}(); + var result = {0}.{2}(test._fld1, test._fld2); + + ValidateResult(test._fld1, test._fld2, result); + }} + + public void RunFldScenario() + {{ + var result = {0}.{2}(_fld1, _fld2); + + ValidateResult(_fld1, _fld2, result); + }} + + public void RunUnsupportedScenario() + {{ + Succeeded = false; + + try + {{ + RunBasicScenario_UnsafeRead(); + }} + catch (PlatformNotSupportedException) + {{ + Succeeded = true; + }} + }} + + private void ValidateResult({5}<{6}> left, {7}<{8}> right, bool result, [CallerMemberName] string method = "") + {{ + {6}[] inArray1 = new {6}[Op1ElementCount]; + {8}[] inArray2 = new {8}[Op2ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + + ValidateResult(inArray1, inArray2, result, method); + }} + + private void ValidateResult(void* left, void* right, bool result, [CallerMemberName] string method = "") + {{ + {6}[] inArray1 = new {6}[Op1ElementCount]; + {8}[] inArray2 = new {8}[Op2ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{6}, byte>(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{8}, byte>(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + + ValidateResult(inArray1, inArray2, result, method); + }} + + private void ValidateResult({6}[] left, {8}[] right, bool result, [CallerMemberName] string method = "") + {{ + var expectedResult1 = true; + + for (var i = 0; i < Op1ElementCount; i++) + {{ + expectedResult1 &= ({12}); + }} + + var expectedResult2 = true; + + for (var i = 0; i < Op1ElementCount; i++) + {{ + expectedResult2 &= ({13}); + }} + + if (((expectedResult1 == false) && (expectedResult2 == false)) != result) + {{ + Succeeded = false; + + Console.WriteLine($"{{nameof({0})}}.{{nameof({0}.{2})}}<{4}>({5}<{6}>, {7}<{8}>): {{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/Shared/BooleanTwoCmpOpTest_DataTable.cs b/tests/src/JIT/HardwareIntrinsics/X86/Shared/BooleanTwoCmpOpTest_DataTable.cs new file mode 100644 index 000000000000..6733d6bf3f23 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Shared/BooleanTwoCmpOpTest_DataTable.cs @@ -0,0 +1,58 @@ +// 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; +using System.Runtime.Intrinsics.X86; + +namespace JIT.HardwareIntrinsics.X86 +{ + public unsafe struct BooleanTwoComparisonOpTest__DataTable : IDisposable + where TOp1 : struct + where TOp2 : struct + { + private byte[] inArray1; + private byte[] inArray2; + + private GCHandle inHandle1; + private GCHandle inHandle2; + + private byte simdSize; + + public BooleanTwoComparisonOpTest__DataTable(TOp1[] inArray1, TOp2[] inArray2, int simdSize) + { + this.inArray1 = new byte[simdSize * 2]; + this.inArray2 = new byte[simdSize * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + + this.simdSize = unchecked((byte)(simdSize)); + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), this.simdSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), this.simdSize); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), simdSize); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), simdSize); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + } + + private static unsafe void* Align(byte* buffer, byte expectedAlignment) + { + // Compute how bad the misalignment is, which is at most (expectedAlignment - 1). + // Then subtract that from the expectedAlignment and add it to the original address + // to compute the aligned address. + + var misalignment = expectedAlignment - ((ulong)(buffer) % expectedAlignment); + return (void*)(buffer + misalignment); + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Shared/BooleanUnOpTest.template b/tests/src/JIT/HardwareIntrinsics/X86/Shared/BooleanUnOpTest.template new file mode 100644 index 000000000000..21623a5bbb91 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Shared/BooleanUnOpTest.template @@ -0,0 +1,283 @@ +// 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.Linq; +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 {2}{4}() + {{ + var test = new BooleanComparisonOpTest__{2}{4}(); + + if (test.IsSupported) + {{ + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if ({1}.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 ({1}.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 ({1}.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 BooleanComparisonOpTest__{2}{4} + {{ + private const int VectorSize = {7}; + + private const int Op1ElementCount = VectorSize / sizeof({6}); + + private static {6}[] _data = new {6}[Op1ElementCount]; + + private static {5}<{6}> _clsVar; + + private {5}<{6}> _fld; + + private BooleanUnaryOpTest__DataTable<{6}> _dataTable; + + static BooleanComparisonOpTest__{2}{4}() + {{ + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) {{ _data[i] = {8}; }} + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{5}<{6}>, byte>(ref _clsVar), ref Unsafe.As<{6}, byte>(ref _data[0]), VectorSize); + }} + + public BooleanComparisonOpTest__{2}{4}() + {{ + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) {{ _data[i] = {8}; }} + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{5}<{6}>, byte>(ref _fld), ref Unsafe.As<{6}, byte>(ref _data[0]), VectorSize); + + for (var i = 0; i < Op1ElementCount; i++) {{ _data[i] = {8}; }} + _dataTable = new BooleanUnaryOpTest__DataTable<{6}>(_data, VectorSize); + }} + + public bool IsSupported => {0}.IsSupported; + + public bool Succeeded {{ get; set; }} + + public void RunBasicScenario_UnsafeRead() + {{ + var result = {0}.{2}( + Unsafe.Read<{5}<{6}>>(_dataTable.inArrayPtr) + ); + + ValidateResult(_dataTable.inArrayPtr, result); + }} + + public void RunBasicScenario_Load() + {{ + var result = {0}.{2}( + {1}.Load{5}(({6}*)(_dataTable.inArrayPtr)) + ); + + ValidateResult(_dataTable.inArrayPtr, result); + }} + + public void RunBasicScenario_LoadAligned() + {{ + var result = {0}.{2}( + {1}.LoadAligned{5}(({6}*)(_dataTable.inArrayPtr)) + ); + + ValidateResult(_dataTable.inArrayPtr, result); + }} + + public void RunReflectionScenario_UnsafeRead() + {{ + var result = typeof({0}).GetMethod(nameof({0}.{2}), new Type[] {{ typeof({5}<{6}>) }}) + .Invoke(null, new object[] {{ + Unsafe.Read<{5}<{6}>>(_dataTable.inArrayPtr) + }}); + + ValidateResult(_dataTable.inArrayPtr, (bool)(result)); + }} + + public void RunReflectionScenario_Load() + {{ + var result = typeof({0}).GetMethod(nameof({0}.{2}), new Type[] {{ typeof({5}<{6}>) }}) + .Invoke(null, new object[] {{ + {1}.Load{5}(({6}*)(_dataTable.inArrayPtr)) + }}); + + ValidateResult(_dataTable.inArrayPtr, (bool)(result)); + }} + + public void RunReflectionScenario_LoadAligned() + {{ + var result = typeof({0}).GetMethod(nameof({0}.{2}), new Type[] {{ typeof({5}<{6}>) }}) + .Invoke(null, new object[] {{ + {1}.LoadAligned{5}(({6}*)(_dataTable.inArrayPtr)) + }}); + + ValidateResult(_dataTable.inArrayPtr, (bool)(result)); + }} + + public void RunClsVarScenario() + {{ + var result = {0}.{2}( + _clsVar + ); + + ValidateResult(_clsVar, result); + }} + + public void RunLclVarScenario_UnsafeRead() + {{ + var value = Unsafe.Read<{5}<{6}>>(_dataTable.inArrayPtr); + var result = {0}.{2}(value); + + ValidateResult(value, result); + }} + + public void RunLclVarScenario_Load() + {{ + var value = {1}.Load{5}(({6}*)(_dataTable.inArrayPtr)); + var result = {0}.{2}(value); + + ValidateResult(value, result); + }} + + public void RunLclVarScenario_LoadAligned() + {{ + var value = {1}.LoadAligned{5}(({6}*)(_dataTable.inArrayPtr)); + var result = {0}.{2}(value); + + ValidateResult(value, result); + }} + + public void RunLclFldScenario() + {{ + var test = new BooleanComparisonOpTest__{2}{4}(); + var result = {0}.{2}(test._fld); + + ValidateResult(test._fld, result); + }} + + public void RunFldScenario() + {{ + var result = {0}.{2}(_fld); + + ValidateResult(_fld, result); + }} + + public void RunUnsupportedScenario() + {{ + Succeeded = false; + + try + {{ + RunBasicScenario_UnsafeRead(); + }} + catch (PlatformNotSupportedException) + {{ + Succeeded = true; + }} + }} + + private void ValidateResult({5}<{6}> value, bool result, [CallerMemberName] string method = "") + {{ + {6}[] inArray = new {6}[Op1ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray[0]), value); + + ValidateResult(inArray, result, method); + }} + + private void ValidateResult(void* value, bool result, [CallerMemberName] string method = "") + {{ + {6}[] inArray = new {6}[Op1ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{6}, byte>(ref inArray[0]), ref Unsafe.AsRef(value), VectorSize); + + ValidateResult(inArray, result, method); + }} + + private void ValidateResult({6}[] value, bool result, [CallerMemberName] string method = "") + {{ + var expectedResult = true; + + for (var i = 0; i < Op1ElementCount; i++) + {{ + expectedResult &= ({9}); + }} + + if (expectedResult != result) + {{ + Succeeded = false; + + Console.WriteLine($"{{nameof({0})}}.{{nameof({0}.{2})}}<{4}>({5}<{6}>): {{method}} failed:"); + Console.WriteLine($" value: ({{string.Join(", ", value)}})"); + Console.WriteLine($" result: ({{string.Join(", ", result)}})"); + Console.WriteLine(); + }} + }} + }} +}} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Shared/BooleanUnOpTest_DataTable.cs b/tests/src/JIT/HardwareIntrinsics/X86/Shared/BooleanUnOpTest_DataTable.cs new file mode 100644 index 000000000000..b38a7b4d3fe3 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Shared/BooleanUnOpTest_DataTable.cs @@ -0,0 +1,50 @@ +// 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; +using System.Runtime.Intrinsics.X86; + +namespace JIT.HardwareIntrinsics.X86 +{ + public unsafe struct BooleanUnaryOpTest__DataTable : IDisposable + where TOp1 : struct + { + private byte[] inArray; + + private GCHandle inHandle; + + private byte simdSize; + + public BooleanUnaryOpTest__DataTable(TOp1[] inArray, int simdSize) + { + this.inArray = new byte[simdSize * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + + this.simdSize = unchecked((byte)(simdSize)); + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), this.simdSize); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), simdSize); + + public void Dispose() + { + inHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, byte expectedAlignment) + { + // Compute how bad the misalignment is, which is at most (expectedAlignment - 1). + // Then subtract that from the expectedAlignment and add it to the original address + // to compute the aligned address. + + var misalignment = expectedAlignment - ((ulong)(buffer) % expectedAlignment); + return (void*)(buffer + misalignment); + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Shared/GenerateTests.csx b/tests/src/JIT/HardwareIntrinsics/X86/Shared/GenerateTests.csx index 5950e9e09c32..d68084744793 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Shared/GenerateTests.csx +++ b/tests/src/JIT/HardwareIntrinsics/X86/Shared/GenerateTests.csx @@ -246,9 +246,99 @@ private static readonly (string templateFileName, string[] templateData)[] Ssse3 private static readonly (string templateFileName, string[] templateData)[] Sse41Inputs = new [] { - // TemplateName Isa, LoadIsa, Method, RetVectorType, RetBaseType, Op1VectorType, Op1BaseType, Op2VectorType, Op2BaseType, Op3VectorType, Op3BaseType, VectorSize, NextValueOp1, NextValueOp2, NextValueOp3, ValidateFirstResult, ValidateRemainingResults - ("SimpleBinOpTest.template", new string[] { "Sse41", "Sse2", "CompareEqual", "Vector128", "Int64", "Vector128", "Int64", "Vector128", "Int64", "16", "(long)(random.Next(int.MinValue, int.MaxValue))", "(long)(random.Next(int.MinValue, int.MaxValue))", "result[0] != ((left[0] == right[0]) ? unchecked((long)(-1)) : 0)", "result[i] != ((left[i] == right[i]) ? unchecked((long)(-1)) : 0)"}), - ("SimpleBinOpTest.template", new string[] { "Sse41", "Sse2", "CompareEqual", "Vector128", "UInt64", "Vector128", "UInt64", "Vector128", "UInt64", "16", "(ulong)(random.Next(0, int.MaxValue))", "(ulong)(random.Next(0, int.MaxValue))", "result[0] != ((left[0] == right[0]) ? unchecked((ulong)(-1)) : 0)", "result[i] != ((left[i] == right[i]) ? unchecked((ulong)(-1)) : 0)"}), + // TemplateName Isa, LoadIsa, Method, RetVectorType, RetBaseType, Op1VectorType, Op1BaseType, Op2VectorType, Op2BaseType, Op3VectorType, Op3BaseType, VectorSize, NextValueOp1, NextValueOp2, NextValueOp3, ValidateFirstResult, ValidateRemainingResults + ("SimpleTernOpTest.template", new string[] { "Sse41", "Sse2", "BlendVariable", "Vector128", "Byte", "Vector128", "Byte", "Vector128", "Byte", "Vector128", "Byte", "16", "(byte)(random.Next(0, byte.MaxValue))", "(byte)(random.Next(0, byte.MaxValue))", "(byte)(((i % 2) == 0) ? 128 : 1)", "((thirdOp[0] >> 7) & 1) == 1 ? secondOp[0] != result[0] : firstOp[0] != result[0]", "((thirdOp[i] >> 7) & 1) == 1 ? secondOp[i] != result[i] : firstOp[i] != result[i]"}), + ("SimpleTernOpTest.template", new string[] { "Sse41", "Sse2", "BlendVariable", "Vector128", "Double", "Vector128", "Double", "Vector128", "Double", "Vector128", "Double", "16", "(double)(random.NextDouble())", "(double)(random.NextDouble())", "(double)(((i % 2) == 0) ? -0.0 : 1.0)", "((BitConverter.DoubleToInt64Bits(thirdOp[0]) >> 63) & 1) == 1 ? BitConverter.DoubleToInt64Bits(secondOp[0]) != BitConverter.DoubleToInt64Bits(result[0]) : BitConverter.DoubleToInt64Bits(firstOp[0]) != BitConverter.DoubleToInt64Bits(result[0])", "((BitConverter.DoubleToInt64Bits(thirdOp[i]) >> 63) & 1) == 1 ? BitConverter.DoubleToInt64Bits(secondOp[i]) != BitConverter.DoubleToInt64Bits(result[i]) : BitConverter.DoubleToInt64Bits(firstOp[i]) != BitConverter.DoubleToInt64Bits(result[i])"}), + ("SimpleTernOpTest.template", new string[] { "Sse41", "Sse2", "BlendVariable", "Vector128", "SByte", "Vector128", "SByte", "Vector128", "SByte", "Vector128", "SByte", "16", "(sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue))", "(sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue))", "(sbyte)(((i % 2) == 0) ? -128 : 1)", "((thirdOp[0] >> 7) & 1) == 1 ? secondOp[0] != result[0] : firstOp[0] != result[0]", "((thirdOp[i] >> 7) & 1) == 1 ? secondOp[i] != result[i] : firstOp[i] != result[i]"}), + ("SimpleTernOpTest.template", new string[] { "Sse41", "Sse", "BlendVariable", "Vector128", "Single", "Vector128", "Single", "Vector128", "Single", "Vector128", "Single", "16", "(float)(random.NextDouble())", "(float)(random.NextDouble())", "(float)(((i % 2) == 0) ? -0.0 : 1.0)", "((BitConverter.SingleToInt32Bits(thirdOp[0]) >> 31) & 1) == 1 ? BitConverter.SingleToInt32Bits(secondOp[0]) != BitConverter.SingleToInt32Bits(result[0]) : BitConverter.SingleToInt32Bits(firstOp[0]) != BitConverter.SingleToInt32Bits(result[0])", "((BitConverter.SingleToInt32Bits(thirdOp[i]) >> 31) & 1) == 1 ? BitConverter.SingleToInt32Bits(secondOp[i]) != BitConverter.SingleToInt32Bits(result[i]) : BitConverter.SingleToInt32Bits(firstOp[i]) != BitConverter.SingleToInt32Bits(result[i])"}), + ("SimpleUnOpTest.template", new string[] { "Sse41", "Sse2", "Ceiling", "Vector128", "Double", "Vector128", "Double", "16", "(double)(random.NextDouble())", "BitConverter.DoubleToInt64Bits(result[0]) != BitConverter.DoubleToInt64Bits(Math.Ceiling(firstOp[0]))", "BitConverter.DoubleToInt64Bits(result[i]) != BitConverter.DoubleToInt64Bits(Math.Ceiling(firstOp[i]))"}), + ("SimpleUnOpTest.template", new string[] { "Sse41", "Sse", "Ceiling", "Vector128", "Single", "Vector128", "Single", "16", "(float)(random.NextDouble())", "BitConverter.SingleToInt32Bits(result[0]) != BitConverter.SingleToInt32Bits(MathF.Ceiling(firstOp[0]))", "BitConverter.SingleToInt32Bits(result[i]) != BitConverter.SingleToInt32Bits(MathF.Ceiling(firstOp[i]))"}), + ("SimpleBinOpTest.template", new string[] { "Sse41", "Sse2", "CeilingScalar", "Vector128", "Double", "Vector128", "Double", "Vector128", "Double", "16", "(double)(random.NextDouble())", "(double)(random.NextDouble())", "BitConverter.DoubleToInt64Bits(result[0]) != BitConverter.DoubleToInt64Bits(Math.Ceiling(right[0]))", "BitConverter.DoubleToInt64Bits(result[i]) != BitConverter.DoubleToInt64Bits(left[i])"}), + ("SimpleBinOpTest.template", new string[] { "Sse41", "Sse", "CeilingScalar", "Vector128", "Single", "Vector128", "Single", "Vector128", "Single", "16", "(float)(random.NextDouble())", "(float)(random.NextDouble())", "BitConverter.SingleToInt32Bits(result[0]) != BitConverter.SingleToInt32Bits(MathF.Ceiling(right[0]))", "BitConverter.SingleToInt32Bits(result[i]) != BitConverter.SingleToInt32Bits(left[i])"}), + ("SimpleBinOpTest.template", new string[] { "Sse41", "Sse2", "CompareEqual", "Vector128", "Int64", "Vector128", "Int64", "Vector128", "Int64", "16", "(long)(random.Next(int.MinValue, int.MaxValue))", "(long)(random.Next(int.MinValue, int.MaxValue))", "result[0] != ((left[0] == right[0]) ? unchecked((long)(-1)) : 0)", "result[i] != ((left[i] == right[i]) ? unchecked((long)(-1)) : 0)"}), + ("SimpleBinOpTest.template", new string[] { "Sse41", "Sse2", "CompareEqual", "Vector128", "UInt64", "Vector128", "UInt64", "Vector128", "UInt64", "16", "(ulong)(random.Next(0, int.MaxValue))", "(ulong)(random.Next(0, int.MaxValue))", "result[0] != ((left[0] == right[0]) ? unchecked((ulong)(-1)) : 0)", "result[i] != ((left[i] == right[i]) ? unchecked((ulong)(-1)) : 0)"}), + ("SimpleUnOpTest.template", new string[] { "Sse41", "Sse2", "Floor", "Vector128", "Double", "Vector128", "Double", "16", "(double)(random.NextDouble())", "BitConverter.DoubleToInt64Bits(result[0]) != BitConverter.DoubleToInt64Bits(Math.Floor(firstOp[0]))", "BitConverter.DoubleToInt64Bits(result[i]) != BitConverter.DoubleToInt64Bits(Math.Floor(firstOp[i]))"}), + ("SimpleUnOpTest.template", new string[] { "Sse41", "Sse", "Floor", "Vector128", "Single", "Vector128", "Single", "16", "(float)(random.NextDouble())", "BitConverter.SingleToInt32Bits(result[0]) != BitConverter.SingleToInt32Bits(MathF.Floor(firstOp[0]))", "BitConverter.SingleToInt32Bits(result[i]) != BitConverter.SingleToInt32Bits(MathF.Floor(firstOp[i]))"}), + ("SimpleBinOpTest.template", new string[] { "Sse41", "Sse2", "FloorScalar", "Vector128", "Double", "Vector128", "Double", "Vector128", "Double", "16", "(double)(random.NextDouble())", "(double)(random.NextDouble())", "BitConverter.DoubleToInt64Bits(result[0]) != BitConverter.DoubleToInt64Bits(Math.Floor(right[0]))", "BitConverter.DoubleToInt64Bits(result[i]) != BitConverter.DoubleToInt64Bits(left[i])"}), + ("SimpleBinOpTest.template", new string[] { "Sse41", "Sse", "FloorScalar", "Vector128", "Single", "Vector128", "Single", "Vector128", "Single", "16", "(float)(random.NextDouble())", "(float)(random.NextDouble())", "BitConverter.SingleToInt32Bits(result[0]) != BitConverter.SingleToInt32Bits(MathF.Floor(right[0]))", "BitConverter.SingleToInt32Bits(result[i]) != BitConverter.SingleToInt32Bits(left[i])"}), + ("SimpleBinOpTest.template", new string[] { "Sse41", "Sse2", "Max", "Vector128", "Int32", "Vector128", "Int32", "Vector128", "Int32", "16", "(int)(random.Next(int.MinValue, int.MaxValue))", "(int)(random.Next(int.MinValue, int.MaxValue))", "result[0] != Math.Max(left[0], right[0])", "result[i] != Math.Max(left[i], right[i])"}), + ("SimpleBinOpTest.template", new string[] { "Sse41", "Sse2", "Max", "Vector128", "SByte", "Vector128", "SByte", "Vector128", "SByte", "16", "(sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue))", "(sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue))", "result[0] != Math.Max(left[0], right[0])", "result[i] != Math.Max(left[i], right[i])"}), + ("SimpleBinOpTest.template", new string[] { "Sse41", "Sse2", "Max", "Vector128", "UInt16", "Vector128", "UInt16", "Vector128", "UInt16", "16", "(ushort)(random.Next(0, ushort.MaxValue))", "(ushort)(random.Next(0, ushort.MaxValue))", "result[0] != Math.Max(left[0], right[0])", "result[i] != Math.Max(left[i], right[i])"}), + ("SimpleBinOpTest.template", new string[] { "Sse41", "Sse2", "Max", "Vector128", "UInt32", "Vector128", "UInt32", "Vector128", "UInt32", "16", "(uint)(random.Next(0, int.MaxValue))", "(uint)(random.Next(0, int.MaxValue))", "result[0] != Math.Max(left[0], right[0])", "result[i] != Math.Max(left[i], right[i])"}), + ("SimpleBinOpTest.template", new string[] { "Sse41", "Sse2", "Min", "Vector128", "Int32", "Vector128", "Int32", "Vector128", "Int32", "16", "(int)(random.Next(int.MinValue, int.MaxValue))", "(int)(random.Next(int.MinValue, int.MaxValue))", "result[0] != Math.Min(left[0], right[0])", "result[i] != Math.Min(left[i], right[i])"}), + ("SimpleBinOpTest.template", new string[] { "Sse41", "Sse2", "Min", "Vector128", "SByte", "Vector128", "SByte", "Vector128", "SByte", "16", "(sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue))", "(sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue))", "result[0] != Math.Min(left[0], right[0])", "result[i] != Math.Min(left[i], right[i])"}), + ("SimpleBinOpTest.template", new string[] { "Sse41", "Sse2", "Min", "Vector128", "UInt16", "Vector128", "UInt16", "Vector128", "UInt16", "16", "(ushort)(random.Next(0, ushort.MaxValue))", "(ushort)(random.Next(0, ushort.MaxValue))", "result[0] != Math.Min(left[0], right[0])", "result[i] != Math.Min(left[i], right[i])"}), + ("SimpleBinOpTest.template", new string[] { "Sse41", "Sse2", "Min", "Vector128", "UInt32", "Vector128", "UInt32", "Vector128", "UInt32", "16", "(uint)(random.Next(0, int.MaxValue))", "(uint)(random.Next(0, int.MaxValue))", "result[0] != Math.Min(left[0], right[0])", "result[i] != Math.Min(left[i], right[i])"}), + ("SimpleBinOpTest.template", new string[] { "Sse41", "Sse2", "MultiplyLow", "Vector128", "Int32", "Vector128", "Int32", "Vector128", "Int32", "16", "(int)(random.Next(int.MinValue, int.MaxValue))", "(int)(random.Next(int.MinValue, int.MaxValue))", "result[0] != BitConverter.ToInt32(BitConverter.GetBytes(((long)(left[0])) * right[0]), 0)", "result[i] != BitConverter.ToInt32(BitConverter.GetBytes(((long)(left[i])) * right[i]), 0)"}), + ("HorizontalBinOpTest.template", new string[] { "Sse41", "Sse2", "PackUnsignedSaturate", "Vector128", "UInt16", "Vector128", "Int32", "Vector128", "Int32", "16", "(int)(random.Next(int.MinValue, int.MaxValue))", "(int)(random.Next(int.MinValue, int.MaxValue))", "result[i1] != ((left[i3 - inner] > 0xFFFF) ? 0xFFFF : ((left[i3 - inner] < 0) ? 0 : BitConverter.ToUInt16(BitConverter.GetBytes(left[i3 - inner]), 0)))", "result[i2] != ((right[i3 - inner] > 0xFFFF) ? 0xFFFF : ((right[i3 - inner] < 0) ? 0 : BitConverter.ToUInt16(BitConverter.GetBytes(right[i3 - inner]), 0)))"}), + ("SimpleUnOpTest.template", new string[] { "Sse41", "Sse2", "RoundCurrentDirection", "Vector128", "Double", "Vector128", "Double", "16", "(double)(random.NextDouble())", "BitConverter.DoubleToInt64Bits(result[0]) != BitConverter.DoubleToInt64Bits(Math.Round(firstOp[0]))", "BitConverter.DoubleToInt64Bits(result[i]) != BitConverter.DoubleToInt64Bits(Math.Round(firstOp[i]))"}), + ("SimpleUnOpTest.template", new string[] { "Sse41", "Sse", "RoundCurrentDirection", "Vector128", "Single", "Vector128", "Single", "16", "(float)(random.NextDouble())", "BitConverter.SingleToInt32Bits(result[0]) != BitConverter.SingleToInt32Bits(MathF.Round(firstOp[0]))", "BitConverter.SingleToInt32Bits(result[i]) != BitConverter.SingleToInt32Bits(MathF.Round(firstOp[i]))"}), + ("SimpleBinOpTest.template", new string[] { "Sse41", "Sse2", "RoundCurrentDirectionScalar", "Vector128", "Double", "Vector128", "Double", "Vector128", "Double", "16", "(double)(random.NextDouble())", "(double)(random.NextDouble())", "BitConverter.DoubleToInt64Bits(result[0]) != BitConverter.DoubleToInt64Bits(Math.Round(right[0]))", "BitConverter.DoubleToInt64Bits(result[i]) != BitConverter.DoubleToInt64Bits(left[i])"}), + ("SimpleBinOpTest.template", new string[] { "Sse41", "Sse", "RoundCurrentDirectionScalar", "Vector128", "Single", "Vector128", "Single", "Vector128", "Single", "16", "(float)(random.NextDouble())", "(float)(random.NextDouble())", "BitConverter.SingleToInt32Bits(result[0]) != BitConverter.SingleToInt32Bits(MathF.Round(right[0]))", "BitConverter.SingleToInt32Bits(result[i]) != BitConverter.SingleToInt32Bits(left[i])"}), + ("SimpleUnOpTest.template", new string[] { "Sse41", "Sse2", "RoundToNearestInteger", "Vector128", "Double", "Vector128", "Double", "16", "(double)(random.NextDouble())", "BitConverter.DoubleToInt64Bits(result[0]) != BitConverter.DoubleToInt64Bits(Math.Round(firstOp[0], MidpointRounding.AwayFromZero))", "BitConverter.DoubleToInt64Bits(result[i]) != BitConverter.DoubleToInt64Bits(Math.Round(firstOp[i], MidpointRounding.AwayFromZero))"}), + ("SimpleUnOpTest.template", new string[] { "Sse41", "Sse", "RoundToNearestInteger", "Vector128", "Single", "Vector128", "Single", "16", "(float)(random.NextDouble())", "BitConverter.SingleToInt32Bits(result[0]) != BitConverter.SingleToInt32Bits(MathF.Round(firstOp[0], MidpointRounding.AwayFromZero))", "BitConverter.SingleToInt32Bits(result[i]) != BitConverter.SingleToInt32Bits(MathF.Round(firstOp[i], MidpointRounding.AwayFromZero))"}), + ("SimpleBinOpTest.template", new string[] { "Sse41", "Sse2", "RoundToNearestIntegerScalar", "Vector128", "Double", "Vector128", "Double", "Vector128", "Double", "16", "(double)(random.NextDouble())", "(double)(random.NextDouble())", "BitConverter.DoubleToInt64Bits(result[0]) != BitConverter.DoubleToInt64Bits(Math.Round(right[0], MidpointRounding.AwayFromZero))", "BitConverter.DoubleToInt64Bits(result[i]) != BitConverter.DoubleToInt64Bits(left[i])"}), + ("SimpleBinOpTest.template", new string[] { "Sse41", "Sse", "RoundToNearestIntegerScalar", "Vector128", "Single", "Vector128", "Single", "Vector128", "Single", "16", "(float)(random.NextDouble())", "(float)(random.NextDouble())", "BitConverter.SingleToInt32Bits(result[0]) != BitConverter.SingleToInt32Bits(MathF.Round(right[0], MidpointRounding.AwayFromZero))", "BitConverter.SingleToInt32Bits(result[i]) != BitConverter.SingleToInt32Bits(left[i])"}), + ("SimpleUnOpTest.template", new string[] { "Sse41", "Sse2", "RoundToNegativeInfinity", "Vector128", "Double", "Vector128", "Double", "16", "(double)(random.NextDouble())", "BitConverter.DoubleToInt64Bits(result[0]) != BitConverter.DoubleToInt64Bits(Math.Floor(firstOp[0]))", "BitConverter.DoubleToInt64Bits(result[i]) != BitConverter.DoubleToInt64Bits(Math.Floor(firstOp[i]))"}), + ("SimpleUnOpTest.template", new string[] { "Sse41", "Sse", "RoundToNegativeInfinity", "Vector128", "Single", "Vector128", "Single", "16", "(float)(random.NextDouble())", "BitConverter.SingleToInt32Bits(result[0]) != BitConverter.SingleToInt32Bits(MathF.Floor(firstOp[0]))", "BitConverter.SingleToInt32Bits(result[i]) != BitConverter.SingleToInt32Bits(MathF.Floor(firstOp[i]))"}), + ("SimpleBinOpTest.template", new string[] { "Sse41", "Sse2", "RoundToNegativeInfinityScalar", "Vector128", "Double", "Vector128", "Double", "Vector128", "Double", "16", "(double)(random.NextDouble())", "(double)(random.NextDouble())", "BitConverter.DoubleToInt64Bits(result[0]) != BitConverter.DoubleToInt64Bits(Math.Floor(right[0]))", "BitConverter.DoubleToInt64Bits(result[i]) != BitConverter.DoubleToInt64Bits(left[i])"}), + ("SimpleBinOpTest.template", new string[] { "Sse41", "Sse", "RoundToNegativeInfinityScalar", "Vector128", "Single", "Vector128", "Single", "Vector128", "Single", "16", "(float)(random.NextDouble())", "(float)(random.NextDouble())", "BitConverter.SingleToInt32Bits(result[0]) != BitConverter.SingleToInt32Bits(MathF.Floor(right[0]))", "BitConverter.SingleToInt32Bits(result[i]) != BitConverter.SingleToInt32Bits(left[i])"}), + ("SimpleUnOpTest.template", new string[] { "Sse41", "Sse2", "RoundToPositiveInfinity", "Vector128", "Double", "Vector128", "Double", "16", "(double)(random.NextDouble())", "BitConverter.DoubleToInt64Bits(result[0]) != BitConverter.DoubleToInt64Bits(Math.Ceiling(firstOp[0]))", "BitConverter.DoubleToInt64Bits(result[i]) != BitConverter.DoubleToInt64Bits(Math.Ceiling(firstOp[i]))"}), + ("SimpleUnOpTest.template", new string[] { "Sse41", "Sse", "RoundToPositiveInfinity", "Vector128", "Single", "Vector128", "Single", "16", "(float)(random.NextDouble())", "BitConverter.SingleToInt32Bits(result[0]) != BitConverter.SingleToInt32Bits(MathF.Ceiling(firstOp[0]))", "BitConverter.SingleToInt32Bits(result[i]) != BitConverter.SingleToInt32Bits(MathF.Ceiling(firstOp[i]))"}), + ("SimpleBinOpTest.template", new string[] { "Sse41", "Sse2", "RoundToPositiveInfinityScalar", "Vector128", "Double", "Vector128", "Double", "Vector128", "Double", "16", "(double)(random.NextDouble())", "(double)(random.NextDouble())", "BitConverter.DoubleToInt64Bits(result[0]) != BitConverter.DoubleToInt64Bits(Math.Ceiling(right[0]))", "BitConverter.DoubleToInt64Bits(result[i]) != BitConverter.DoubleToInt64Bits(left[i])"}), + ("SimpleBinOpTest.template", new string[] { "Sse41", "Sse", "RoundToPositiveInfinityScalar", "Vector128", "Single", "Vector128", "Single", "Vector128", "Single", "16", "(float)(random.NextDouble())", "(float)(random.NextDouble())", "BitConverter.SingleToInt32Bits(result[0]) != BitConverter.SingleToInt32Bits(MathF.Ceiling(right[0]))", "BitConverter.SingleToInt32Bits(result[i]) != BitConverter.SingleToInt32Bits(left[i])"}), + ("SimpleUnOpTest.template", new string[] { "Sse41", "Sse2", "RoundToZero", "Vector128", "Double", "Vector128", "Double", "16", "(double)(random.NextDouble())", "BitConverter.DoubleToInt64Bits(result[0]) != BitConverter.DoubleToInt64Bits((firstOp[0] > 0) ? Math.Floor(firstOp[0]) : Math.Ceiling(firstOp[0]))", "BitConverter.DoubleToInt64Bits(result[i]) != BitConverter.DoubleToInt64Bits((firstOp[i] > 0) ? Math.Floor(firstOp[i]) : Math.Ceiling(firstOp[i]))"}), + ("SimpleUnOpTest.template", new string[] { "Sse41", "Sse", "RoundToZero", "Vector128", "Single", "Vector128", "Single", "16", "(float)(random.NextDouble())", "BitConverter.SingleToInt32Bits(result[0]) != BitConverter.SingleToInt32Bits((firstOp[0] > 0) ? MathF.Floor(firstOp[0]) : MathF.Ceiling(firstOp[0]))", "BitConverter.SingleToInt32Bits(result[i]) != BitConverter.SingleToInt32Bits((firstOp[i] > 0) ? MathF.Floor(firstOp[i]) : MathF.Ceiling(firstOp[i]))"}), + ("SimpleBinOpTest.template", new string[] { "Sse41", "Sse2", "RoundToZeroScalar", "Vector128", "Double", "Vector128", "Double", "Vector128", "Double", "16", "(double)(random.NextDouble())", "(double)(random.NextDouble())", "BitConverter.DoubleToInt64Bits(result[0]) != BitConverter.DoubleToInt64Bits((right[0] > 0) ? Math.Floor(right[0]) : Math.Ceiling(right[0]))", "BitConverter.DoubleToInt64Bits(result[i]) != BitConverter.DoubleToInt64Bits(left[i])"}), + ("SimpleBinOpTest.template", new string[] { "Sse41", "Sse", "RoundToZeroScalar", "Vector128", "Single", "Vector128", "Single", "Vector128", "Single", "16", "(float)(random.NextDouble())", "(float)(random.NextDouble())", "BitConverter.SingleToInt32Bits(result[0]) != BitConverter.SingleToInt32Bits((right[0] > 0) ? MathF.Floor(right[0]) : MathF.Ceiling(right[0]))", "BitConverter.SingleToInt32Bits(result[i]) != BitConverter.SingleToInt32Bits(left[i])"}), + ("BooleanUnOpTest.template", new string[] { "Sse41", "Sse2", "TestAllOnes", "Vector128", "Byte", "Vector128", "Byte", "16", "(byte)(random.Next(0, byte.MaxValue))", "(~value[i] & byte.MaxValue) == 0"}), + ("BooleanUnOpTest.template", new string[] { "Sse41", "Sse2", "TestAllOnes", "Vector128", "Int16", "Vector128", "Int16", "16", "(short)(random.Next(short.MinValue, short.MaxValue))", "(~value[i] & -1) == 0"}), + ("BooleanUnOpTest.template", new string[] { "Sse41", "Sse2", "TestAllOnes", "Vector128", "Int32", "Vector128", "Int32", "16", "(int)(random.Next(int.MinValue, int.MaxValue))", "(~value[i] & -1) == 0"}), + ("BooleanUnOpTest.template", new string[] { "Sse41", "Sse2", "TestAllOnes", "Vector128", "Int64", "Vector128", "Int64", "16", "(long)(random.Next(int.MinValue, int.MaxValue))", "(~value[i] & -1) == 0"}), + ("BooleanUnOpTest.template", new string[] { "Sse41", "Sse2", "TestAllOnes", "Vector128", "SByte", "Vector128", "SByte", "16", "(sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue))", "(~value[i] & -1) == 0"}), + ("BooleanUnOpTest.template", new string[] { "Sse41", "Sse2", "TestAllOnes", "Vector128", "UInt16", "Vector128", "UInt16", "16", "(ushort)(random.Next(0, ushort.MaxValue))", "(~value[i] & ushort.MaxValue) == 0"}), + ("BooleanUnOpTest.template", new string[] { "Sse41", "Sse2", "TestAllOnes", "Vector128", "UInt32", "Vector128", "UInt32", "16", "(uint)(random.Next(0, int.MaxValue))", "(~value[i] & uint.MaxValue) == 0"}), + ("BooleanUnOpTest.template", new string[] { "Sse41", "Sse2", "TestAllOnes", "Vector128", "UInt64", "Vector128", "UInt64", "16", "(ulong)(random.Next(0, int.MaxValue))", "(~value[i] & ulong.MaxValue) == 0"}), + ("BooleanBinOpTest.template", new string[] { "Sse41", "Sse2", "TestAllZeros", "Vector128", "Byte", "Vector128", "Byte", "Vector128", "Byte", "16", "(byte)(random.Next(0, byte.MaxValue))", "(byte)(random.Next(0, byte.MaxValue))", "(left[i] & right[i]) == 0"}), + ("BooleanBinOpTest.template", new string[] { "Sse41", "Sse2", "TestAllZeros", "Vector128", "Int16", "Vector128", "Int16", "Vector128", "Int16", "16", "(short)(random.Next(short.MinValue, short.MaxValue))", "(short)(random.Next(short.MinValue, short.MaxValue))", "(left[i] & right[i]) == 0"}), + ("BooleanBinOpTest.template", new string[] { "Sse41", "Sse2", "TestAllZeros", "Vector128", "Int32", "Vector128", "Int32", "Vector128", "Int32", "16", "(int)(random.Next(int.MinValue, int.MaxValue))", "(int)(random.Next(int.MinValue, int.MaxValue))", "(left[i] & right[i]) == 0"}), + ("BooleanBinOpTest.template", new string[] { "Sse41", "Sse2", "TestAllZeros", "Vector128", "Int64", "Vector128", "Int64", "Vector128", "Int64", "16", "(long)(random.Next(int.MinValue, int.MaxValue))", "(long)(random.Next(int.MinValue, int.MaxValue))", "(left[i] & right[i]) == 0"}), + ("BooleanBinOpTest.template", new string[] { "Sse41", "Sse2", "TestAllZeros", "Vector128", "SByte", "Vector128", "SByte", "Vector128", "SByte", "16", "(sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue))", "(sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue))", "(left[i] & right[i]) == 0"}), + ("BooleanBinOpTest.template", new string[] { "Sse41", "Sse2", "TestAllZeros", "Vector128", "UInt16", "Vector128", "UInt16", "Vector128", "UInt16", "16", "(ushort)(random.Next(0, ushort.MaxValue))", "(ushort)(random.Next(0, ushort.MaxValue))", "(left[i] & right[i]) == 0"}), + ("BooleanBinOpTest.template", new string[] { "Sse41", "Sse2", "TestAllZeros", "Vector128", "UInt32", "Vector128", "UInt32", "Vector128", "UInt32", "16", "(uint)(random.Next(0, int.MaxValue))", "(uint)(random.Next(0, int.MaxValue))", "(left[i] & right[i]) == 0"}), + ("BooleanBinOpTest.template", new string[] { "Sse41", "Sse2", "TestAllZeros", "Vector128", "UInt64", "Vector128", "UInt64", "Vector128", "UInt64", "16", "(ulong)(random.Next(0, int.MaxValue))", "(ulong)(random.Next(0, int.MaxValue))", "(left[i] & right[i]) == 0"}), + ("BooleanBinOpTest.template", new string[] { "Sse41", "Sse2", "TestC", "Vector128", "Byte", "Vector128", "Byte", "Vector128", "Byte", "16", "(byte)(random.Next(0, byte.MaxValue))", "(byte)(random.Next(0, byte.MaxValue))", "(~left[i] & right[i]) == 0"}), + ("BooleanBinOpTest.template", new string[] { "Sse41", "Sse2", "TestC", "Vector128", "Int16", "Vector128", "Int16", "Vector128", "Int16", "16", "(short)(random.Next(short.MinValue, short.MaxValue))", "(short)(random.Next(short.MinValue, short.MaxValue))", "(~left[i] & right[i]) == 0"}), + ("BooleanBinOpTest.template", new string[] { "Sse41", "Sse2", "TestC", "Vector128", "Int32", "Vector128", "Int32", "Vector128", "Int32", "16", "(int)(random.Next(int.MinValue, int.MaxValue))", "(int)(random.Next(int.MinValue, int.MaxValue))", "(~left[i] & right[i]) == 0"}), + ("BooleanBinOpTest.template", new string[] { "Sse41", "Sse2", "TestC", "Vector128", "Int64", "Vector128", "Int64", "Vector128", "Int64", "16", "(long)(random.Next(int.MinValue, int.MaxValue))", "(long)(random.Next(int.MinValue, int.MaxValue))", "(~left[i] & right[i]) == 0"}), + ("BooleanBinOpTest.template", new string[] { "Sse41", "Sse2", "TestC", "Vector128", "SByte", "Vector128", "SByte", "Vector128", "SByte", "16", "(sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue))", "(sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue))", "(~left[i] & right[i]) == 0"}), + ("BooleanBinOpTest.template", new string[] { "Sse41", "Sse2", "TestC", "Vector128", "UInt16", "Vector128", "UInt16", "Vector128", "UInt16", "16", "(ushort)(random.Next(0, ushort.MaxValue))", "(ushort)(random.Next(0, ushort.MaxValue))", "(~left[i] & right[i]) == 0"}), + ("BooleanBinOpTest.template", new string[] { "Sse41", "Sse2", "TestC", "Vector128", "UInt32", "Vector128", "UInt32", "Vector128", "UInt32", "16", "(uint)(random.Next(0, int.MaxValue))", "(uint)(random.Next(0, int.MaxValue))", "(~left[i] & right[i]) == 0"}), + ("BooleanBinOpTest.template", new string[] { "Sse41", "Sse2", "TestC", "Vector128", "UInt64", "Vector128", "UInt64", "Vector128", "UInt64", "16", "(ulong)(random.Next(0, int.MaxValue))", "(ulong)(random.Next(0, int.MaxValue))", "(~left[i] & right[i]) == 0"}), + ("BooleanTwoCmpOpTest.template", new string[] { "Sse41", "Sse2", "TestMixOnesZeros", "Vector128", "Byte", "Vector128", "Byte", "Vector128", "Byte", "16", "(byte)(random.Next(0, byte.MaxValue))", "(byte)(random.Next(0, byte.MaxValue))", "((left[i] & right[i]) == 0)", "((~left[i] & right[i]) == 0)"}), + ("BooleanTwoCmpOpTest.template", new string[] { "Sse41", "Sse2", "TestMixOnesZeros", "Vector128", "Int16", "Vector128", "Int16", "Vector128", "Int16", "16", "(short)(random.Next(short.MinValue, short.MaxValue))", "(short)(random.Next(short.MinValue, short.MaxValue))", "((left[i] & right[i]) == 0)", "((~left[i] & right[i]) == 0)"}), + ("BooleanTwoCmpOpTest.template", new string[] { "Sse41", "Sse2", "TestMixOnesZeros", "Vector128", "Int32", "Vector128", "Int32", "Vector128", "Int32", "16", "(int)(random.Next(int.MinValue, int.MaxValue))", "(int)(random.Next(int.MinValue, int.MaxValue))", "((left[i] & right[i]) == 0)", "((~left[i] & right[i]) == 0)"}), + ("BooleanTwoCmpOpTest.template", new string[] { "Sse41", "Sse2", "TestMixOnesZeros", "Vector128", "Int64", "Vector128", "Int64", "Vector128", "Int64", "16", "(long)(random.Next(int.MinValue, int.MaxValue))", "(long)(random.Next(int.MinValue, int.MaxValue))", "((left[i] & right[i]) == 0)", "((~left[i] & right[i]) == 0)"}), + ("BooleanTwoCmpOpTest.template", new string[] { "Sse41", "Sse2", "TestMixOnesZeros", "Vector128", "SByte", "Vector128", "SByte", "Vector128", "SByte", "16", "(sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue))", "(sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue))", "((left[i] & right[i]) == 0)", "((~left[i] & right[i]) == 0)"}), + ("BooleanTwoCmpOpTest.template", new string[] { "Sse41", "Sse2", "TestMixOnesZeros", "Vector128", "UInt16", "Vector128", "UInt16", "Vector128", "UInt16", "16", "(ushort)(random.Next(0, ushort.MaxValue))", "(ushort)(random.Next(0, ushort.MaxValue))", "((left[i] & right[i]) == 0)", "((~left[i] & right[i]) == 0)"}), + ("BooleanTwoCmpOpTest.template", new string[] { "Sse41", "Sse2", "TestMixOnesZeros", "Vector128", "UInt32", "Vector128", "UInt32", "Vector128", "UInt32", "16", "(uint)(random.Next(0, int.MaxValue))", "(uint)(random.Next(0, int.MaxValue))", "((left[i] & right[i]) == 0)", "((~left[i] & right[i]) == 0)"}), + ("BooleanTwoCmpOpTest.template", new string[] { "Sse41", "Sse2", "TestMixOnesZeros", "Vector128", "UInt64", "Vector128", "UInt64", "Vector128", "UInt64", "16", "(ulong)(random.Next(0, int.MaxValue))", "(ulong)(random.Next(0, int.MaxValue))", "((left[i] & right[i]) == 0)", "((~left[i] & right[i]) == 0)"}), + ("BooleanTwoCmpOpTest.template", new string[] { "Sse41", "Sse2", "TestNotZAndNotC", "Vector128", "Byte", "Vector128", "Byte", "Vector128", "Byte", "16", "(byte)(random.Next(0, byte.MaxValue))", "(byte)(random.Next(0, byte.MaxValue))", "((left[i] & right[i]) == 0)", "((~left[i] & right[i]) == 0)"}), + ("BooleanTwoCmpOpTest.template", new string[] { "Sse41", "Sse2", "TestNotZAndNotC", "Vector128", "Int16", "Vector128", "Int16", "Vector128", "Int16", "16", "(short)(random.Next(short.MinValue, short.MaxValue))", "(short)(random.Next(short.MinValue, short.MaxValue))", "((left[i] & right[i]) == 0)", "((~left[i] & right[i]) == 0)"}), + ("BooleanTwoCmpOpTest.template", new string[] { "Sse41", "Sse2", "TestNotZAndNotC", "Vector128", "Int32", "Vector128", "Int32", "Vector128", "Int32", "16", "(int)(random.Next(int.MinValue, int.MaxValue))", "(int)(random.Next(int.MinValue, int.MaxValue))", "((left[i] & right[i]) == 0)", "((~left[i] & right[i]) == 0)"}), + ("BooleanTwoCmpOpTest.template", new string[] { "Sse41", "Sse2", "TestNotZAndNotC", "Vector128", "Int64", "Vector128", "Int64", "Vector128", "Int64", "16", "(long)(random.Next(int.MinValue, int.MaxValue))", "(long)(random.Next(int.MinValue, int.MaxValue))", "((left[i] & right[i]) == 0)", "((~left[i] & right[i]) == 0)"}), + ("BooleanTwoCmpOpTest.template", new string[] { "Sse41", "Sse2", "TestNotZAndNotC", "Vector128", "SByte", "Vector128", "SByte", "Vector128", "SByte", "16", "(sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue))", "(sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue))", "((left[i] & right[i]) == 0)", "((~left[i] & right[i]) == 0)"}), + ("BooleanTwoCmpOpTest.template", new string[] { "Sse41", "Sse2", "TestNotZAndNotC", "Vector128", "UInt16", "Vector128", "UInt16", "Vector128", "UInt16", "16", "(ushort)(random.Next(0, ushort.MaxValue))", "(ushort)(random.Next(0, ushort.MaxValue))", "((left[i] & right[i]) == 0)", "((~left[i] & right[i]) == 0)"}), + ("BooleanTwoCmpOpTest.template", new string[] { "Sse41", "Sse2", "TestNotZAndNotC", "Vector128", "UInt32", "Vector128", "UInt32", "Vector128", "UInt32", "16", "(uint)(random.Next(0, int.MaxValue))", "(uint)(random.Next(0, int.MaxValue))", "((left[i] & right[i]) == 0)", "((~left[i] & right[i]) == 0)"}), + ("BooleanTwoCmpOpTest.template", new string[] { "Sse41", "Sse2", "TestNotZAndNotC", "Vector128", "UInt64", "Vector128", "UInt64", "Vector128", "UInt64", "16", "(ulong)(random.Next(0, int.MaxValue))", "(ulong)(random.Next(0, int.MaxValue))", "((left[i] & right[i]) == 0)", "((~left[i] & right[i]) == 0)"}), + ("BooleanBinOpTest.template", new string[] { "Sse41", "Sse2", "TestZ", "Vector128", "Byte", "Vector128", "Byte", "Vector128", "Byte", "16", "(byte)(random.Next(0, byte.MaxValue))", "(byte)(random.Next(0, byte.MaxValue))", "(left[i] & right[i]) == 0"}), + ("BooleanBinOpTest.template", new string[] { "Sse41", "Sse2", "TestZ", "Vector128", "Int16", "Vector128", "Int16", "Vector128", "Int16", "16", "(short)(random.Next(short.MinValue, short.MaxValue))", "(short)(random.Next(short.MinValue, short.MaxValue))", "(left[i] & right[i]) == 0"}), + ("BooleanBinOpTest.template", new string[] { "Sse41", "Sse2", "TestZ", "Vector128", "Int32", "Vector128", "Int32", "Vector128", "Int32", "16", "(int)(random.Next(int.MinValue, int.MaxValue))", "(int)(random.Next(int.MinValue, int.MaxValue))", "(left[i] & right[i]) == 0"}), + ("BooleanBinOpTest.template", new string[] { "Sse41", "Sse2", "TestZ", "Vector128", "Int64", "Vector128", "Int64", "Vector128", "Int64", "16", "(long)(random.Next(int.MinValue, int.MaxValue))", "(long)(random.Next(int.MinValue, int.MaxValue))", "(left[i] & right[i]) == 0"}), + ("BooleanBinOpTest.template", new string[] { "Sse41", "Sse2", "TestZ", "Vector128", "SByte", "Vector128", "SByte", "Vector128", "SByte", "16", "(sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue))", "(sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue))", "(left[i] & right[i]) == 0"}), + ("BooleanBinOpTest.template", new string[] { "Sse41", "Sse2", "TestZ", "Vector128", "UInt16", "Vector128", "UInt16", "Vector128", "UInt16", "16", "(ushort)(random.Next(0, ushort.MaxValue))", "(ushort)(random.Next(0, ushort.MaxValue))", "(left[i] & right[i]) == 0"}), + ("BooleanBinOpTest.template", new string[] { "Sse41", "Sse2", "TestZ", "Vector128", "UInt32", "Vector128", "UInt32", "Vector128", "UInt32", "16", "(uint)(random.Next(0, int.MaxValue))", "(uint)(random.Next(0, int.MaxValue))", "(left[i] & right[i]) == 0"}), + ("BooleanBinOpTest.template", new string[] { "Sse41", "Sse2", "TestZ", "Vector128", "UInt64", "Vector128", "UInt64", "Vector128", "UInt64", "16", "(ulong)(random.Next(0, int.MaxValue))", "(ulong)(random.Next(0, int.MaxValue))", "(left[i] & right[i]) == 0"}), }; private static readonly (string templateFileName, string[] templateData)[] Sse42Inputs = new [] diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Shared/HorizontalBinOpTest.template b/tests/src/JIT/HardwareIntrinsics/X86/Shared/HorizontalBinOpTest.template index c3a45dfa7071..08611f7acda6 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Shared/HorizontalBinOpTest.template +++ b/tests/src/JIT/HardwareIntrinsics/X86/Shared/HorizontalBinOpTest.template @@ -303,11 +303,11 @@ namespace JIT.HardwareIntrinsics.X86 {{ for (var outer = 0; outer < (VectorSize / 16); outer++) {{ - for (var inner = 0; inner < (8 / sizeof({6})); inner++) + for (var inner = 0; inner < (8 / sizeof({4})); inner++) {{ - var i1 = (outer * (16 / sizeof({6}))) + inner; - var i2 = i1 + (8 / sizeof({6})); - var i3 = (outer * (16 / sizeof({6}))) + (inner * 2); + var i1 = (outer * (16 / sizeof({4}))) + inner; + var i2 = i1 + (8 / sizeof({4})); + var i3 = (outer * (16 / sizeof({4}))) + (inner * 2); if ({12}) {{ diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse41/Blend.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/Blend.cs new file mode 100644 index 000000000000..8617f8e28eb7 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/Blend.cs @@ -0,0 +1,424 @@ +// 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 (Sse41.IsSupported) + { + using (TestTable floatTable = new TestTable(new float[4] { 1, -5, 100, 0 }, new float[4] { 22, -1, -50, 0 }, new float[4])) + { + var vf1 = Unsafe.Read>(floatTable.inArray1Ptr); + var vf2 = Unsafe.Read>(floatTable.inArray2Ptr); + + // SDDD + var vf3 = Sse41.Blend(vf1, vf2, 1); + Unsafe.Write(floatTable.outArrayPtr, vf3); + + if (!floatTable.CheckResult((x, y, z) => (z[0] == y[0]) && (z[1] == x[1]) && + (z[2] == x[2]) && (z[3] == x[3]))) + { + Console.WriteLine("SSE41 Blend failed on float:"); + foreach (var item in floatTable.outArray) + { + Console.Write(item + ", "); + } + Console.WriteLine(); + testResult = Fail; + } + + // DSDD + vf3 = Sse41.Blend(vf1, vf2, 2); + Unsafe.Write(floatTable.outArrayPtr, vf3); + + if (!floatTable.CheckResult((x, y, z) => (z[0] == x[0]) && (z[1] == y[1]) && + (z[2] == x[2]) && (z[3] == x[3]))) + { + Console.WriteLine("SSE41 Blend failed on float:"); + foreach (var item in floatTable.outArray) + { + Console.Write(item + ", "); + } + Console.WriteLine(); + testResult = Fail; + } + + // DDSD + vf3 = Sse41.Blend(vf1, vf2, 4); + Unsafe.Write(floatTable.outArrayPtr, vf3); + + if (!floatTable.CheckResult((x, y, z) => (z[0] == x[0]) && (z[1] == x[1]) && + (z[2] == y[2]) && (z[3] == x[3]))) + { + Console.WriteLine("SSE41 Blend failed on float:"); + foreach (var item in floatTable.outArray) + { + Console.Write(item + ", "); + } + Console.WriteLine(); + testResult = Fail; + } + + // SDSD + vf3 = Sse41.Blend(vf1, vf2, 85); + Unsafe.Write(floatTable.outArrayPtr, vf3); + + if (!floatTable.CheckResult((x, y, z) => (z[0] == y[0]) && (z[1] == x[1]) && + (z[2] == y[2]) && (z[3] == x[3]))) + { + Console.WriteLine("SSE41 Blend failed on float:"); + foreach (var item in floatTable.outArray) + { + Console.Write(item + ", "); + } + Console.WriteLine(); + testResult = Fail; + } + + // SDDD + vf3 = (Vector128)typeof(Sse41).GetMethod(nameof(Sse41.Blend), new Type[] { vf1.GetType(), vf2.GetType(), typeof(byte) }).Invoke(null, new object[] { vf1, vf2, (byte)(1) }); + Unsafe.Write(floatTable.outArrayPtr, vf3); + + if (!floatTable.CheckResult((x, y, z) => (z[0] == y[0]) && (z[1] == x[1]) && + (z[2] == x[2]) && (z[3] == x[3]))) + { + Console.WriteLine("SSE41 Blend failed on float:"); + foreach (var item in floatTable.outArray) + { + Console.Write(item + ", "); + } + Console.WriteLine(); + testResult = Fail; + } + } + + using (TestTable doubleTable = new TestTable(new double[2] { 1, -5 }, new double[2] { 22, -1 }, new double[2])) + { + var vf1 = Unsafe.Read>(doubleTable.inArray1Ptr); + var vf2 = Unsafe.Read>(doubleTable.inArray2Ptr); + + // DD + var vf3 = Sse41.Blend(vf1, vf2, 0); + Unsafe.Write(doubleTable.outArrayPtr, vf3); + + if (!doubleTable.CheckResult((x, y, z) => (z[0] == x[0]) && (z[1] == x[1]))) + { + Console.WriteLine("SSE41 Blend failed on double:"); + foreach (var item in doubleTable.outArray) + { + Console.Write(item + ", "); + } + Console.WriteLine(); + testResult = Fail; + } + + // SD + vf3 = Sse41.Blend(vf1, vf2, 1); + Unsafe.Write(doubleTable.outArrayPtr, vf3); + + if (!doubleTable.CheckResult((x, y, z) => (z[0] == y[0]) && (z[1] == x[1]))) + { + Console.WriteLine("SSE41 Blend failed on double:"); + foreach (var item in doubleTable.outArray) + { + Console.Write(item + ", "); + } + Console.WriteLine(); + testResult = Fail; + } + + // DS + vf3 = Sse41.Blend(vf1, vf2, 2); + Unsafe.Write(doubleTable.outArrayPtr, vf3); + + if (!doubleTable.CheckResult((x, y, z) => (z[0] == x[0]) && (z[1] == y[1]))) + { + Console.WriteLine("SSE41 Blend failed on double:"); + foreach (var item in doubleTable.outArray) + { + Console.Write(item + ", "); + } + Console.WriteLine(); + testResult = Fail; + } + + // SS + vf3 = Sse41.Blend(vf1, vf2, 51); + Unsafe.Write(doubleTable.outArrayPtr, vf3); + + if (!doubleTable.CheckResult((x, y, z) => (z[0] == y[0]) && (z[1] == y[1]))) + { + Console.WriteLine("SSE41 Blend failed on double:"); + foreach (var item in doubleTable.outArray) + { + Console.Write(item + ", "); + } + Console.WriteLine(); + testResult = Fail; + } + + // SDDD + vf3 = (Vector128)typeof(Sse41).GetMethod(nameof(Sse41.Blend), new Type[] { vf1.GetType(), vf2.GetType(), typeof(byte) }).Invoke(null, new object[] { vf1, vf2, (byte)(0) }); + Unsafe.Write(doubleTable.outArrayPtr, vf3); + + if (!doubleTable.CheckResult((x, y, z) => (z[0] == x[0]) && (z[1] == x[1]))) + { + Console.WriteLine("SSE41 Blend failed on double:"); + foreach (var item in doubleTable.outArray) + { + Console.Write(item + ", "); + } + Console.WriteLine(); + testResult = Fail; + } + } + + using (TestTable shortTable = new TestTable(new short[8] { 1, -5, 100, 0, 1, -5, 100, 0 }, new short[8] { 22, -1, -50, 0, 22, -1, -50, 0 }, new short[8])) + { + var vf1 = Unsafe.Read>(shortTable.inArray1Ptr); + var vf2 = Unsafe.Read>(shortTable.inArray2Ptr); + + // SDDD DDDD + var vf3 = Sse41.Blend(vf1, vf2, 1); + Unsafe.Write(shortTable.outArrayPtr, vf3); + + if (!shortTable.CheckResult((x, y, z) => (z[0] == y[0]) && (z[1] == x[1]) && + (z[2] == x[2]) && (z[3] == x[3]) && + (z[4] == x[4]) && (z[5] == x[5]) && + (z[6] == x[6]) && (z[7] == x[7]))) + { + Console.WriteLine("SSE41 Blend failed on short:"); + foreach (var item in shortTable.outArray) + { + Console.Write(item + ", "); + } + Console.WriteLine(); + testResult = Fail; + } + + // DSDD DDDD + vf3 = Sse41.Blend(vf1, vf2, 2); + Unsafe.Write(shortTable.outArrayPtr, vf3); + + if (!shortTable.CheckResult((x, y, z) => (z[0] == x[0]) && (z[1] == y[1]) && + (z[2] == x[2]) && (z[3] == x[3]) && + (z[4] == x[4]) && (z[5] == x[5]) && + (z[6] == x[6]) && (z[7] == x[7]))) + { + Console.WriteLine("SSE41 Blend failed on short:"); + foreach (var item in shortTable.outArray) + { + Console.Write(item + ", "); + } + Console.WriteLine(); + testResult = Fail; + } + + // DDSD DDDD + vf3 = Sse41.Blend(vf1, vf2, 4); + Unsafe.Write(shortTable.outArrayPtr, vf3); + + if (!shortTable.CheckResult((x, y, z) => (z[0] == x[0]) && (z[1] == x[1]) && + (z[2] == y[2]) && (z[3] == x[3]) && + (z[4] == x[4]) && (z[5] == x[5]) && + (z[6] == x[6]) && (z[7] == x[7]))) + { + Console.WriteLine("SSE41 Blend failed on short:"); + foreach (var item in shortTable.outArray) + { + Console.Write(item + ", "); + } + Console.WriteLine(); + testResult = Fail; + } + + // SDSD SDSD + vf3 = Sse41.Blend(vf1, vf2, 85); + Unsafe.Write(shortTable.outArrayPtr, vf3); + + if (!shortTable.CheckResult((x, y, z) => (z[0] == y[0]) && (z[1] == x[1]) && + (z[2] == y[2]) && (z[3] == x[3]) && + (z[4] == y[4]) && (z[5] == x[5]) && + (z[6] == y[6]) && (z[7] == x[7]))) + { + Console.WriteLine("SSE41 Blend failed on short:"); + foreach (var item in shortTable.outArray) + { + Console.Write(item + ", "); + } + Console.WriteLine(); + testResult = Fail; + } + + // SDDD DDDD + vf3 = (Vector128)typeof(Sse41).GetMethod(nameof(Sse41.Blend), new Type[] { vf1.GetType(), vf2.GetType(), typeof(byte) }).Invoke(null, new object[] { vf1, vf2, (byte)(1) }); + Unsafe.Write(shortTable.outArrayPtr, vf3); + + if (!shortTable.CheckResult((x, y, z) => (z[0] == y[0]) && (z[1] == x[1]) && + (z[2] == x[2]) && (z[3] == x[3]) && + (z[4] == x[4]) && (z[5] == x[5]) && + (z[6] == x[6]) && (z[7] == x[7]))) + { + Console.WriteLine("SSE41 Blend failed on short:"); + foreach (var item in shortTable.outArray) + { + Console.Write(item + ", "); + } + Console.WriteLine(); + testResult = Fail; + } + } + + using (TestTable ushortTable = new TestTable(new ushort[8] { 1, 5, 100, 0, 1, 5, 100, 0 }, new ushort[8] { 22, 1, 50, 0, 22, 1, 50, 0 }, new ushort[8])) + { + var vf1 = Unsafe.Read>(ushortTable.inArray1Ptr); + var vf2 = Unsafe.Read>(ushortTable.inArray2Ptr); + + // SDDD DDDD + var vf3 = Sse41.Blend(vf1, vf2, 1); + Unsafe.Write(ushortTable.outArrayPtr, vf3); + + if (!ushortTable.CheckResult((x, y, z) => (z[0] == y[0]) && (z[1] == x[1]) && + (z[2] == x[2]) && (z[3] == x[3]) && + (z[4] == x[4]) && (z[5] == x[5]) && + (z[6] == x[6]) && (z[7] == x[7]))) + { + Console.WriteLine("SSE41 Blend failed on ushort:"); + foreach (var item in ushortTable.outArray) + { + Console.Write(item + ", "); + } + Console.WriteLine(); + testResult = Fail; + } + + // DSDD DDDD + vf3 = Sse41.Blend(vf1, vf2, 2); + Unsafe.Write(ushortTable.outArrayPtr, vf3); + + if (!ushortTable.CheckResult((x, y, z) => (z[0] == x[0]) && (z[1] == y[1]) && + (z[2] == x[2]) && (z[3] == x[3]) && + (z[4] == x[4]) && (z[5] == x[5]) && + (z[6] == x[6]) && (z[7] == x[7]))) + { + Console.WriteLine("SSE41 Blend failed on ushort:"); + foreach (var item in ushortTable.outArray) + { + Console.Write(item + ", "); + } + Console.WriteLine(); + testResult = Fail; + } + + // DDSD DDDD + vf3 = Sse41.Blend(vf1, vf2, 4); + Unsafe.Write(ushortTable.outArrayPtr, vf3); + + if (!ushortTable.CheckResult((x, y, z) => (z[0] == x[0]) && (z[1] == x[1]) && + (z[2] == y[2]) && (z[3] == x[3]) && + (z[4] == x[4]) && (z[5] == x[5]) && + (z[6] == x[6]) && (z[7] == x[7]))) + { + Console.WriteLine("SSE41 Blend failed on ushort:"); + foreach (var item in ushortTable.outArray) + { + Console.Write(item + ", "); + } + Console.WriteLine(); + testResult = Fail; + } + + // SDSD SDSD + vf3 = Sse41.Blend(vf1, vf2, 85); + Unsafe.Write(ushortTable.outArrayPtr, vf3); + + if (!ushortTable.CheckResult((x, y, z) => (z[0] == y[0]) && (z[1] == x[1]) && + (z[2] == y[2]) && (z[3] == x[3]) && + (z[4] == y[4]) && (z[5] == x[5]) && + (z[6] == y[6]) && (z[7] == x[7]))) + { + Console.WriteLine("SSE41 Blend failed on ushort:"); + foreach (var item in ushortTable.outArray) + { + Console.Write(item + ", "); + } + Console.WriteLine(); + testResult = Fail; + } + + // SDDD DDDD + vf3 = (Vector128)typeof(Sse41).GetMethod(nameof(Sse41.Blend), new Type[] { vf1.GetType(), vf2.GetType(), typeof(byte) }).Invoke(null, new object[] { vf1, vf2, (byte)(1) }); + Unsafe.Write(ushortTable.outArrayPtr, vf3); + + if (!ushortTable.CheckResult((x, y, z) => (z[0] == y[0]) && (z[1] == x[1]) && + (z[2] == x[2]) && (z[3] == x[3]) && + (z[4] == x[4]) && (z[5] == x[5]) && + (z[6] == x[6]) && (z[7] == x[7]))) + { + Console.WriteLine("SSE41 Blend failed on ushort:"); + foreach (var item in ushortTable.outArray) + { + Console.Write(item + ", "); + } + Console.WriteLine(); + testResult = Fail; + } + } + } + + return testResult; + } + + public unsafe struct TestTable : IDisposable where T : struct + { + public T[] inArray1; + public T[] inArray2; + public T[] outArray; + + public void* inArray1Ptr => inHandle1.AddrOfPinnedObject().ToPointer(); + public void* inArray2Ptr => inHandle2.AddrOfPinnedObject().ToPointer(); + public void* outArrayPtr => outHandle.AddrOfPinnedObject().ToPointer(); + + GCHandle inHandle1; + GCHandle inHandle2; + GCHandle outHandle; + public TestTable(T[] a, T[] b, T[] c) + { + this.inArray1 = a; + this.inArray2 = b; + this.outArray = c; + + inHandle1 = GCHandle.Alloc(inArray1, GCHandleType.Pinned); + inHandle2 = GCHandle.Alloc(inArray2, GCHandleType.Pinned); + outHandle = GCHandle.Alloc(outArray, GCHandleType.Pinned); + } + public bool CheckResult(Func check) + { + return check(inArray1, inArray2, outArray); + } + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse41/BlendVariable.Byte.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/BlendVariable.Byte.cs new file mode 100644 index 000000000000..83d013da2894 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/BlendVariable.Byte.cs @@ -0,0 +1,354 @@ +// 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 BlendVariableByte() + { + var test = new SimpleTernaryOpTest__BlendVariableByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Sse2.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 (Sse2.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 (Sse2.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 SimpleTernaryOpTest__BlendVariableByte + { + private const int VectorSize = 16; + + private const int Op1ElementCount = VectorSize / sizeof(Byte); + private const int Op2ElementCount = VectorSize / sizeof(Byte); + private const int Op3ElementCount = VectorSize / sizeof(Byte); + private const int RetElementCount = VectorSize / sizeof(Byte); + + private static Byte[] _data1 = new Byte[Op1ElementCount]; + private static Byte[] _data2 = new Byte[Op2ElementCount]; + private static Byte[] _data3 = new Byte[Op3ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + private static Vector128 _clsVar3; + + private Vector128 _fld1; + private Vector128 _fld2; + private Vector128 _fld3; + + private SimpleTernaryOpTest__DataTable _dataTable; + + static SimpleTernaryOpTest__BlendVariableByte() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (byte)(random.Next(0, byte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (byte)(random.Next(0, byte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), VectorSize); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = (byte)(((i % 2) == 0) ? 128 : 1); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar3), ref Unsafe.As(ref _data3[0]), VectorSize); + } + + public SimpleTernaryOpTest__BlendVariableByte() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (byte)(random.Next(0, byte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (byte)(random.Next(0, byte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), VectorSize); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = (byte)(((i % 2) == 0) ? 128 : 1); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld3), ref Unsafe.As(ref _data3[0]), VectorSize); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (byte)(random.Next(0, byte.MaxValue)); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (byte)(random.Next(0, byte.MaxValue)); } + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = (byte)(((i % 2) == 0) ? 128 : 1); } + _dataTable = new SimpleTernaryOpTest__DataTable(_data1, _data2, _data3, new Byte[RetElementCount], VectorSize); + } + + public bool IsSupported => Sse41.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse41.BlendVariable( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse41.BlendVariable( + Sse2.LoadVector128((Byte*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Byte*)(_dataTable.inArray2Ptr)), + Sse2.LoadVector128((Byte*)(_dataTable.inArray3Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse41.BlendVariable( + Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray2Ptr)), + Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray3Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.BlendVariable), new Type[] { typeof(Vector128), typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.BlendVariable), new Type[] { typeof(Vector128), typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Byte*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Byte*)(_dataTable.inArray2Ptr)), + Sse2.LoadVector128((Byte*)(_dataTable.inArray3Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.BlendVariable), new Type[] { typeof(Vector128), typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray2Ptr)), + Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray3Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse41.BlendVariable( + _clsVar1, + _clsVar2, + _clsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var firstOp = Unsafe.Read>(_dataTable.inArray1Ptr); + var secondOp = Unsafe.Read>(_dataTable.inArray2Ptr); + var thirdOp = Unsafe.Read>(_dataTable.inArray3Ptr); + var result = Sse41.BlendVariable(firstOp, secondOp, thirdOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, thirdOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var firstOp = Sse2.LoadVector128((Byte*)(_dataTable.inArray1Ptr)); + var secondOp = Sse2.LoadVector128((Byte*)(_dataTable.inArray2Ptr)); + var thirdOp = Sse2.LoadVector128((Byte*)(_dataTable.inArray3Ptr)); + var result = Sse41.BlendVariable(firstOp, secondOp, thirdOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, thirdOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var firstOp = Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray1Ptr)); + var secondOp = Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray2Ptr)); + var thirdOp = Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray3Ptr)); + var result = Sse41.BlendVariable(firstOp, secondOp, thirdOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, thirdOp, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleTernaryOpTest__BlendVariableByte(); + var result = Sse41.BlendVariable(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse41.BlendVariable(_fld1, _fld2, _fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128 firstOp, Vector128 secondOp, Vector128 thirdOp, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + Byte[] inArray2 = new Byte[Op2ElementCount]; + Byte[] inArray3 = new Byte[Op3ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), firstOp); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), secondOp); + Unsafe.Write(Unsafe.AsPointer(ref inArray3[0]), thirdOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(void* firstOp, void* secondOp, void* thirdOp, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + Byte[] inArray2 = new Byte[Op2ElementCount]; + Byte[] inArray3 = new Byte[Op3ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(firstOp), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(secondOp), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray3[0]), ref Unsafe.AsRef(thirdOp), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(Byte[] firstOp, Byte[] secondOp, Byte[] thirdOp, Byte[] result, [CallerMemberName] string method = "") + { + if (((thirdOp[0] >> 7) & 1) == 1 ? secondOp[0] != result[0] : firstOp[0] != result[0]) + { + Succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (((thirdOp[i] >> 7) & 1) == 1 ? secondOp[i] != result[i] : firstOp[i] != result[i]) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Sse41)}.{nameof(Sse41.BlendVariable)}(Vector128, Vector128, Vector128): {method} failed:"); + Console.WriteLine($" firstOp: ({string.Join(", ", firstOp)})"); + Console.WriteLine($" secondOp: ({string.Join(", ", secondOp)})"); + Console.WriteLine($" thirdOp: ({string.Join(", ", thirdOp)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse41/BlendVariable.Double.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/BlendVariable.Double.cs new file mode 100644 index 000000000000..780323bc33b9 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/BlendVariable.Double.cs @@ -0,0 +1,354 @@ +// 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 BlendVariableDouble() + { + var test = new SimpleTernaryOpTest__BlendVariableDouble(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Sse2.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 (Sse2.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 (Sse2.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 SimpleTernaryOpTest__BlendVariableDouble + { + private const int VectorSize = 16; + + private const int Op1ElementCount = VectorSize / sizeof(Double); + private const int Op2ElementCount = VectorSize / sizeof(Double); + private const int Op3ElementCount = 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 Double[] _data3 = new Double[Op3ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + private static Vector128 _clsVar3; + + private Vector128 _fld1; + private Vector128 _fld2; + private Vector128 _fld3; + + private SimpleTernaryOpTest__DataTable _dataTable; + + static SimpleTernaryOpTest__BlendVariableDouble() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (double)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (double)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), VectorSize); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = (double)(((i % 2) == 0) ? -0.0 : 1.0); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar3), ref Unsafe.As(ref _data3[0]), VectorSize); + } + + public SimpleTernaryOpTest__BlendVariableDouble() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (double)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (double)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), VectorSize); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = (double)(((i % 2) == 0) ? -0.0 : 1.0); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld3), ref Unsafe.As(ref _data3[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()); } + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = (double)(((i % 2) == 0) ? -0.0 : 1.0); } + _dataTable = new SimpleTernaryOpTest__DataTable(_data1, _data2, _data3, new Double[RetElementCount], VectorSize); + } + + public bool IsSupported => Sse41.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse41.BlendVariable( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse41.BlendVariable( + Sse2.LoadVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Double*)(_dataTable.inArray2Ptr)), + Sse2.LoadVector128((Double*)(_dataTable.inArray3Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse41.BlendVariable( + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray2Ptr)), + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray3Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.BlendVariable), new Type[] { typeof(Vector128), typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.BlendVariable), new Type[] { typeof(Vector128), typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Double*)(_dataTable.inArray2Ptr)), + Sse2.LoadVector128((Double*)(_dataTable.inArray3Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.BlendVariable), new Type[] { typeof(Vector128), typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray2Ptr)), + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray3Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse41.BlendVariable( + _clsVar1, + _clsVar2, + _clsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var firstOp = Unsafe.Read>(_dataTable.inArray1Ptr); + var secondOp = Unsafe.Read>(_dataTable.inArray2Ptr); + var thirdOp = Unsafe.Read>(_dataTable.inArray3Ptr); + var result = Sse41.BlendVariable(firstOp, secondOp, thirdOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, thirdOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var firstOp = Sse2.LoadVector128((Double*)(_dataTable.inArray1Ptr)); + var secondOp = Sse2.LoadVector128((Double*)(_dataTable.inArray2Ptr)); + var thirdOp = Sse2.LoadVector128((Double*)(_dataTable.inArray3Ptr)); + var result = Sse41.BlendVariable(firstOp, secondOp, thirdOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, thirdOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var firstOp = Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray1Ptr)); + var secondOp = Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray2Ptr)); + var thirdOp = Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray3Ptr)); + var result = Sse41.BlendVariable(firstOp, secondOp, thirdOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, thirdOp, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleTernaryOpTest__BlendVariableDouble(); + var result = Sse41.BlendVariable(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse41.BlendVariable(_fld1, _fld2, _fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128 firstOp, Vector128 secondOp, Vector128 thirdOp, void* result, [CallerMemberName] string method = "") + { + Double[] inArray1 = new Double[Op1ElementCount]; + Double[] inArray2 = new Double[Op2ElementCount]; + Double[] inArray3 = new Double[Op3ElementCount]; + Double[] outArray = new Double[RetElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), firstOp); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), secondOp); + Unsafe.Write(Unsafe.AsPointer(ref inArray3[0]), thirdOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(void* firstOp, void* secondOp, void* thirdOp, void* result, [CallerMemberName] string method = "") + { + Double[] inArray1 = new Double[Op1ElementCount]; + Double[] inArray2 = new Double[Op2ElementCount]; + Double[] inArray3 = new Double[Op3ElementCount]; + Double[] outArray = new Double[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(firstOp), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(secondOp), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray3[0]), ref Unsafe.AsRef(thirdOp), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(Double[] firstOp, Double[] secondOp, Double[] thirdOp, Double[] result, [CallerMemberName] string method = "") + { + if (((BitConverter.DoubleToInt64Bits(thirdOp[0]) >> 63) & 1) == 1 ? BitConverter.DoubleToInt64Bits(secondOp[0]) != BitConverter.DoubleToInt64Bits(result[0]) : BitConverter.DoubleToInt64Bits(firstOp[0]) != BitConverter.DoubleToInt64Bits(result[0])) + { + Succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (((BitConverter.DoubleToInt64Bits(thirdOp[i]) >> 63) & 1) == 1 ? BitConverter.DoubleToInt64Bits(secondOp[i]) != BitConverter.DoubleToInt64Bits(result[i]) : BitConverter.DoubleToInt64Bits(firstOp[i]) != BitConverter.DoubleToInt64Bits(result[i])) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Sse41)}.{nameof(Sse41.BlendVariable)}(Vector128, Vector128, Vector128): {method} failed:"); + Console.WriteLine($" firstOp: ({string.Join(", ", firstOp)})"); + Console.WriteLine($" secondOp: ({string.Join(", ", secondOp)})"); + Console.WriteLine($" thirdOp: ({string.Join(", ", thirdOp)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse41/BlendVariable.SByte.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/BlendVariable.SByte.cs new file mode 100644 index 000000000000..e1dd0cbd2789 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/BlendVariable.SByte.cs @@ -0,0 +1,354 @@ +// 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 BlendVariableSByte() + { + var test = new SimpleTernaryOpTest__BlendVariableSByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Sse2.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 (Sse2.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 (Sse2.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 SimpleTernaryOpTest__BlendVariableSByte + { + private const int VectorSize = 16; + + private const int Op1ElementCount = VectorSize / sizeof(SByte); + private const int Op2ElementCount = VectorSize / sizeof(SByte); + private const int Op3ElementCount = VectorSize / sizeof(SByte); + private const int RetElementCount = VectorSize / sizeof(SByte); + + private static SByte[] _data1 = new SByte[Op1ElementCount]; + private static SByte[] _data2 = new SByte[Op2ElementCount]; + private static SByte[] _data3 = new SByte[Op3ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + private static Vector128 _clsVar3; + + private Vector128 _fld1; + private Vector128 _fld2; + private Vector128 _fld3; + + private SimpleTernaryOpTest__DataTable _dataTable; + + static SimpleTernaryOpTest__BlendVariableSByte() + { + 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, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), VectorSize); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = (sbyte)(((i % 2) == 0) ? -128 : 1); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar3), ref Unsafe.As(ref _data3[0]), VectorSize); + } + + public SimpleTernaryOpTest__BlendVariableSByte() + { + 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, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), VectorSize); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = (sbyte)(((i % 2) == 0) ? -128 : 1); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld3), ref Unsafe.As(ref _data3[0]), VectorSize); + + 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)); } + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = (sbyte)(((i % 2) == 0) ? -128 : 1); } + _dataTable = new SimpleTernaryOpTest__DataTable(_data1, _data2, _data3, new SByte[RetElementCount], VectorSize); + } + + public bool IsSupported => Sse41.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse41.BlendVariable( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse41.BlendVariable( + Sse2.LoadVector128((SByte*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((SByte*)(_dataTable.inArray2Ptr)), + Sse2.LoadVector128((SByte*)(_dataTable.inArray3Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse41.BlendVariable( + Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArray2Ptr)), + Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArray3Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.BlendVariable), new Type[] { typeof(Vector128), typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.BlendVariable), new Type[] { typeof(Vector128), typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((SByte*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((SByte*)(_dataTable.inArray2Ptr)), + Sse2.LoadVector128((SByte*)(_dataTable.inArray3Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.BlendVariable), new Type[] { typeof(Vector128), typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArray2Ptr)), + Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArray3Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse41.BlendVariable( + _clsVar1, + _clsVar2, + _clsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var firstOp = Unsafe.Read>(_dataTable.inArray1Ptr); + var secondOp = Unsafe.Read>(_dataTable.inArray2Ptr); + var thirdOp = Unsafe.Read>(_dataTable.inArray3Ptr); + var result = Sse41.BlendVariable(firstOp, secondOp, thirdOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, thirdOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var firstOp = Sse2.LoadVector128((SByte*)(_dataTable.inArray1Ptr)); + var secondOp = Sse2.LoadVector128((SByte*)(_dataTable.inArray2Ptr)); + var thirdOp = Sse2.LoadVector128((SByte*)(_dataTable.inArray3Ptr)); + var result = Sse41.BlendVariable(firstOp, secondOp, thirdOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, thirdOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var firstOp = Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArray1Ptr)); + var secondOp = Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArray2Ptr)); + var thirdOp = Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArray3Ptr)); + var result = Sse41.BlendVariable(firstOp, secondOp, thirdOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, thirdOp, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleTernaryOpTest__BlendVariableSByte(); + var result = Sse41.BlendVariable(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse41.BlendVariable(_fld1, _fld2, _fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128 firstOp, Vector128 secondOp, Vector128 thirdOp, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + SByte[] inArray3 = new SByte[Op3ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), firstOp); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), secondOp); + Unsafe.Write(Unsafe.AsPointer(ref inArray3[0]), thirdOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(void* firstOp, void* secondOp, void* thirdOp, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + SByte[] inArray3 = new SByte[Op3ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(firstOp), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(secondOp), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray3[0]), ref Unsafe.AsRef(thirdOp), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(SByte[] firstOp, SByte[] secondOp, SByte[] thirdOp, SByte[] result, [CallerMemberName] string method = "") + { + if (((thirdOp[0] >> 7) & 1) == 1 ? secondOp[0] != result[0] : firstOp[0] != result[0]) + { + Succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (((thirdOp[i] >> 7) & 1) == 1 ? secondOp[i] != result[i] : firstOp[i] != result[i]) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Sse41)}.{nameof(Sse41.BlendVariable)}(Vector128, Vector128, Vector128): {method} failed:"); + Console.WriteLine($" firstOp: ({string.Join(", ", firstOp)})"); + Console.WriteLine($" secondOp: ({string.Join(", ", secondOp)})"); + Console.WriteLine($" thirdOp: ({string.Join(", ", thirdOp)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse41/BlendVariable.Single.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/BlendVariable.Single.cs new file mode 100644 index 000000000000..d588508e670d --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/BlendVariable.Single.cs @@ -0,0 +1,354 @@ +// 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 BlendVariableSingle() + { + var test = new SimpleTernaryOpTest__BlendVariableSingle(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Sse.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 (Sse.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 (Sse.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 SimpleTernaryOpTest__BlendVariableSingle + { + private const int VectorSize = 16; + + private const int Op1ElementCount = VectorSize / sizeof(Single); + private const int Op2ElementCount = VectorSize / sizeof(Single); + private const int Op3ElementCount = 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 Single[] _data3 = new Single[Op3ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + private static Vector128 _clsVar3; + + private Vector128 _fld1; + private Vector128 _fld2; + private Vector128 _fld3; + + private SimpleTernaryOpTest__DataTable _dataTable; + + static SimpleTernaryOpTest__BlendVariableSingle() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (float)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (float)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), VectorSize); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = (float)(((i % 2) == 0) ? -0.0 : 1.0); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar3), ref Unsafe.As(ref _data3[0]), VectorSize); + } + + public SimpleTernaryOpTest__BlendVariableSingle() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (float)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (float)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), VectorSize); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = (float)(((i % 2) == 0) ? -0.0 : 1.0); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld3), ref Unsafe.As(ref _data3[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()); } + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = (float)(((i % 2) == 0) ? -0.0 : 1.0); } + _dataTable = new SimpleTernaryOpTest__DataTable(_data1, _data2, _data3, new Single[RetElementCount], VectorSize); + } + + public bool IsSupported => Sse41.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse41.BlendVariable( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse41.BlendVariable( + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray3Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse41.BlendVariable( + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray3Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.BlendVariable), new Type[] { typeof(Vector128), typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.BlendVariable), new Type[] { typeof(Vector128), typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray3Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.BlendVariable), new Type[] { typeof(Vector128), typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray3Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse41.BlendVariable( + _clsVar1, + _clsVar2, + _clsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var firstOp = Unsafe.Read>(_dataTable.inArray1Ptr); + var secondOp = Unsafe.Read>(_dataTable.inArray2Ptr); + var thirdOp = Unsafe.Read>(_dataTable.inArray3Ptr); + var result = Sse41.BlendVariable(firstOp, secondOp, thirdOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, thirdOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var firstOp = Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)); + var secondOp = Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)); + var thirdOp = Sse.LoadVector128((Single*)(_dataTable.inArray3Ptr)); + var result = Sse41.BlendVariable(firstOp, secondOp, thirdOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, thirdOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var firstOp = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)); + var secondOp = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)); + var thirdOp = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray3Ptr)); + var result = Sse41.BlendVariable(firstOp, secondOp, thirdOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, thirdOp, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleTernaryOpTest__BlendVariableSingle(); + var result = Sse41.BlendVariable(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse41.BlendVariable(_fld1, _fld2, _fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128 firstOp, Vector128 secondOp, Vector128 thirdOp, void* result, [CallerMemberName] string method = "") + { + Single[] inArray1 = new Single[Op1ElementCount]; + Single[] inArray2 = new Single[Op2ElementCount]; + Single[] inArray3 = new Single[Op3ElementCount]; + Single[] outArray = new Single[RetElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), firstOp); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), secondOp); + Unsafe.Write(Unsafe.AsPointer(ref inArray3[0]), thirdOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(void* firstOp, void* secondOp, void* thirdOp, void* result, [CallerMemberName] string method = "") + { + Single[] inArray1 = new Single[Op1ElementCount]; + Single[] inArray2 = new Single[Op2ElementCount]; + Single[] inArray3 = new Single[Op3ElementCount]; + Single[] outArray = new Single[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(firstOp), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(secondOp), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray3[0]), ref Unsafe.AsRef(thirdOp), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(Single[] firstOp, Single[] secondOp, Single[] thirdOp, Single[] result, [CallerMemberName] string method = "") + { + if (((BitConverter.SingleToInt32Bits(thirdOp[0]) >> 31) & 1) == 1 ? BitConverter.SingleToInt32Bits(secondOp[0]) != BitConverter.SingleToInt32Bits(result[0]) : BitConverter.SingleToInt32Bits(firstOp[0]) != BitConverter.SingleToInt32Bits(result[0])) + { + Succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (((BitConverter.SingleToInt32Bits(thirdOp[i]) >> 31) & 1) == 1 ? BitConverter.SingleToInt32Bits(secondOp[i]) != BitConverter.SingleToInt32Bits(result[i]) : BitConverter.SingleToInt32Bits(firstOp[i]) != BitConverter.SingleToInt32Bits(result[i])) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Sse41)}.{nameof(Sse41.BlendVariable)}(Vector128, Vector128, Vector128): {method} failed:"); + Console.WriteLine($" firstOp: ({string.Join(", ", firstOp)})"); + Console.WriteLine($" secondOp: ({string.Join(", ", secondOp)})"); + Console.WriteLine($" thirdOp: ({string.Join(", ", thirdOp)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse41/Blend_r.csproj b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/Blend_r.csproj new file mode 100644 index 000000000000..20cc49df8bc3 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/Blend_r.csproj @@ -0,0 +1,34 @@ + + + + + Debug + AnyCPU + 2.0 + {95DFC527-4DC1-495E-97D7-E94EE1F7140D} + Exe + {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + ..\..\ + true + + + + + + + False + + + + None + + + + + + + + + + + diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse41/Blend_ro.csproj b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/Blend_ro.csproj new file mode 100644 index 000000000000..884ea632bd81 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/Blend_ro.csproj @@ -0,0 +1,34 @@ + + + + + Debug + AnyCPU + 2.0 + {95DFC527-4DC1-495E-97D7-E94EE1F7140D} + Exe + {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + ..\..\ + true + + + + + + + False + + + + None + True + + + + + + + + + + diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse41/Ceiling.Double.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/Ceiling.Double.cs new file mode 100644 index 000000000000..bf992e8dc2d8 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/Ceiling.Double.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 CeilingDouble() + { + var test = new SimpleUnaryOpTest__CeilingDouble(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Sse2.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 (Sse2.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 (Sse2.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__CeilingDouble + { + private const int VectorSize = 16; + + private const int Op1ElementCount = VectorSize / sizeof(Double); + private const int RetElementCount = VectorSize / sizeof(Double); + + private static Double[] _data = new Double[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private SimpleUnaryOpTest__DataTable _dataTable; + + static SimpleUnaryOpTest__CeilingDouble() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (double)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), VectorSize); + } + + public SimpleUnaryOpTest__CeilingDouble() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (double)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), VectorSize); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (double)(random.NextDouble()); } + _dataTable = new SimpleUnaryOpTest__DataTable(_data, new Double[RetElementCount], VectorSize); + } + + public bool IsSupported => Sse41.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse41.Ceiling( + Unsafe.Read>(_dataTable.inArrayPtr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse41.Ceiling( + Sse2.LoadVector128((Double*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse41.Ceiling( + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.Ceiling), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.Ceiling), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Double*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.Ceiling), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse41.Ceiling( + _clsVar + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = Sse41.Ceiling(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var firstOp = Sse2.LoadVector128((Double*)(_dataTable.inArrayPtr)); + var result = Sse41.Ceiling(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var firstOp = Sse2.LoadAlignedVector128((Double*)(_dataTable.inArrayPtr)); + var result = Sse41.Ceiling(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleUnaryOpTest__CeilingDouble(); + var result = Sse41.Ceiling(test._fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse41.Ceiling(_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 firstOp, void* result, [CallerMemberName] string method = "") + { + Double[] inArray = new Double[Op1ElementCount]; + Double[] outArray = new Double[RetElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Double[] inArray = new Double[Op1ElementCount]; + Double[] outArray = new Double[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Double[] firstOp, Double[] result, [CallerMemberName] string method = "") + { + if (BitConverter.DoubleToInt64Bits(result[0]) != BitConverter.DoubleToInt64Bits(Math.Ceiling(firstOp[0]))) + { + Succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (BitConverter.DoubleToInt64Bits(result[i]) != BitConverter.DoubleToInt64Bits(Math.Ceiling(firstOp[i]))) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Sse41)}.{nameof(Sse41.Ceiling)}(Vector128): {method} failed:"); + Console.WriteLine($" firstOp: ({string.Join(", ", firstOp)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse41/Ceiling.Single.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/Ceiling.Single.cs new file mode 100644 index 000000000000..55a154f438fe --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/Ceiling.Single.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 CeilingSingle() + { + var test = new SimpleUnaryOpTest__CeilingSingle(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Sse.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 (Sse.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 (Sse.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__CeilingSingle + { + private const int VectorSize = 16; + + private const int Op1ElementCount = VectorSize / sizeof(Single); + private const int RetElementCount = VectorSize / sizeof(Single); + + private static Single[] _data = new Single[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private SimpleUnaryOpTest__DataTable _dataTable; + + static SimpleUnaryOpTest__CeilingSingle() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (float)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), VectorSize); + } + + public SimpleUnaryOpTest__CeilingSingle() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (float)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), VectorSize); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (float)(random.NextDouble()); } + _dataTable = new SimpleUnaryOpTest__DataTable(_data, new Single[RetElementCount], VectorSize); + } + + public bool IsSupported => Sse41.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse41.Ceiling( + Unsafe.Read>(_dataTable.inArrayPtr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse41.Ceiling( + Sse.LoadVector128((Single*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse41.Ceiling( + Sse.LoadAlignedVector128((Single*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.Ceiling), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.Ceiling), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadVector128((Single*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.Ceiling), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadAlignedVector128((Single*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse41.Ceiling( + _clsVar + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = Sse41.Ceiling(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var firstOp = Sse.LoadVector128((Single*)(_dataTable.inArrayPtr)); + var result = Sse41.Ceiling(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var firstOp = Sse.LoadAlignedVector128((Single*)(_dataTable.inArrayPtr)); + var result = Sse41.Ceiling(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleUnaryOpTest__CeilingSingle(); + var result = Sse41.Ceiling(test._fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse41.Ceiling(_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 firstOp, void* result, [CallerMemberName] string method = "") + { + Single[] inArray = new Single[Op1ElementCount]; + Single[] outArray = new Single[RetElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Single[] inArray = new Single[Op1ElementCount]; + Single[] outArray = new Single[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Single[] firstOp, Single[] result, [CallerMemberName] string method = "") + { + if (BitConverter.SingleToInt32Bits(result[0]) != BitConverter.SingleToInt32Bits(MathF.Ceiling(firstOp[0]))) + { + Succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (BitConverter.SingleToInt32Bits(result[i]) != BitConverter.SingleToInt32Bits(MathF.Ceiling(firstOp[i]))) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Sse41)}.{nameof(Sse41.Ceiling)}(Vector128): {method} failed:"); + Console.WriteLine($" firstOp: ({string.Join(", ", firstOp)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse41/CeilingScalar.Double.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/CeilingScalar.Double.cs new file mode 100644 index 000000000000..be34065c6c97 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/CeilingScalar.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 CeilingScalarDouble() + { + var test = new SimpleBinaryOpTest__CeilingScalarDouble(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Sse2.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 (Sse2.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 (Sse2.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__CeilingScalarDouble + { + private const int VectorSize = 16; + + 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 Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private SimpleBinaryOpTest__DataTable _dataTable; + + static SimpleBinaryOpTest__CeilingScalarDouble() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (double)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (double)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), VectorSize); + } + + public SimpleBinaryOpTest__CeilingScalarDouble() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (double)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (double)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(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(_data1, _data2, new Double[RetElementCount], VectorSize); + } + + public bool IsSupported => Sse41.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse41.CeilingScalar( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse41.CeilingScalar( + Sse2.LoadVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Double*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse41.CeilingScalar( + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.CeilingScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.CeilingScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Double*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.CeilingScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse41.CeilingScalar( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read>(_dataTable.inArray1Ptr); + var right = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = Sse41.CeilingScalar(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((Double*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((Double*)(_dataTable.inArray2Ptr)); + var result = Sse41.CeilingScalar(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray2Ptr)); + var result = Sse41.CeilingScalar(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__CeilingScalarDouble(); + var result = Sse41.CeilingScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse41.CeilingScalar(_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(Vector128 left, Vector128 right, void* result, [CallerMemberName] string method = "") + { + Double[] inArray1 = new Double[Op1ElementCount]; + Double[] inArray2 = new Double[Op2ElementCount]; + Double[] outArray = new Double[RetElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(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(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(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(Math.Ceiling(right[0]))) + { + Succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (BitConverter.DoubleToInt64Bits(result[i]) != BitConverter.DoubleToInt64Bits(left[i])) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Sse41)}.{nameof(Sse41.CeilingScalar)}(Vector128, Vector128): {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/Sse41/CeilingScalar.Single.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/CeilingScalar.Single.cs new file mode 100644 index 000000000000..062e94977e9e --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/CeilingScalar.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 CeilingScalarSingle() + { + var test = new SimpleBinaryOpTest__CeilingScalarSingle(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Sse.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 (Sse.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 (Sse.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__CeilingScalarSingle + { + private const int VectorSize = 16; + + 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 Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private SimpleBinaryOpTest__DataTable _dataTable; + + static SimpleBinaryOpTest__CeilingScalarSingle() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (float)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (float)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), VectorSize); + } + + public SimpleBinaryOpTest__CeilingScalarSingle() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (float)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (float)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(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(_data1, _data2, new Single[RetElementCount], VectorSize); + } + + public bool IsSupported => Sse41.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse41.CeilingScalar( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse41.CeilingScalar( + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse41.CeilingScalar( + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.CeilingScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.CeilingScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.CeilingScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse41.CeilingScalar( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read>(_dataTable.inArray1Ptr); + var right = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = Sse41.CeilingScalar(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse41.CeilingScalar(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse41.CeilingScalar(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__CeilingScalarSingle(); + var result = Sse41.CeilingScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse41.CeilingScalar(_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(Vector128 left, Vector128 right, void* result, [CallerMemberName] string method = "") + { + Single[] inArray1 = new Single[Op1ElementCount]; + Single[] inArray2 = new Single[Op2ElementCount]; + Single[] outArray = new Single[RetElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(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(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(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(MathF.Ceiling(right[0]))) + { + Succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (BitConverter.SingleToInt32Bits(result[i]) != BitConverter.SingleToInt32Bits(left[i])) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Sse41)}.{nameof(Sse41.CeilingScalar)}(Vector128, Vector128): {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/Sse41/ConvertToVector128Int16.Byte.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/ConvertToVector128Int16.Byte.cs new file mode 100644 index 000000000000..724262161aa0 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/ConvertToVector128Int16.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 ConvertToVector128Int16Byte() + { + var test = new SimpleUnaryOpTest__ConvertToVector128Int16Byte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Sse2.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 (Sse2.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 (Sse2.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__ConvertToVector128Int16Byte + { + private const int VectorSize = 16; + + private const int Op1ElementCount = VectorSize / sizeof(Byte); + private const int RetElementCount = VectorSize / sizeof(Int16); + + private static Byte[] _data = new Byte[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private SimpleUnaryOpTest__DataTable _dataTable; + + static SimpleUnaryOpTest__ConvertToVector128Int16Byte() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (byte)(random.Next(0, byte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), VectorSize); + } + + public SimpleUnaryOpTest__ConvertToVector128Int16Byte() + { + 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, byte>(ref _fld), ref Unsafe.As(ref _data[0]), VectorSize); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (byte)(random.Next(0, byte.MaxValue)); } + _dataTable = new SimpleUnaryOpTest__DataTable(_data, new Int16[RetElementCount], VectorSize); + } + + public bool IsSupported => Sse41.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse41.ConvertToVector128Int16( + Unsafe.Read>(_dataTable.inArrayPtr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse41.ConvertToVector128Int16( + Sse2.LoadVector128((Byte*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse41.ConvertToVector128Int16( + Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.ConvertToVector128Int16), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.ConvertToVector128Int16), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Byte*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.ConvertToVector128Int16), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse41.ConvertToVector128Int16( + _clsVar + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = Sse41.ConvertToVector128Int16(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var firstOp = Sse2.LoadVector128((Byte*)(_dataTable.inArrayPtr)); + var result = Sse41.ConvertToVector128Int16(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var firstOp = Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArrayPtr)); + var result = Sse41.ConvertToVector128Int16(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleUnaryOpTest__ConvertToVector128Int16Byte(); + var result = Sse41.ConvertToVector128Int16(test._fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse41.ConvertToVector128Int16(_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 firstOp, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray = new Byte[Op1ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray = new Byte[Op1ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Byte[] 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(Sse41)}.{nameof(Sse41.ConvertToVector128Int16)}(Vector128): {method} failed:"); + Console.WriteLine($" firstOp: ({string.Join(", ", firstOp)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse41/ConvertToVector128Int16.SByte.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/ConvertToVector128Int16.SByte.cs new file mode 100644 index 000000000000..4d989351070f --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/ConvertToVector128Int16.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 ConvertToVector128Int16SByte() + { + var test = new SimpleUnaryOpTest__ConvertToVector128Int16SByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Sse2.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 (Sse2.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 (Sse2.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__ConvertToVector128Int16SByte + { + private const int VectorSize = 16; + + private const int Op1ElementCount = VectorSize / sizeof(SByte); + private const int RetElementCount = VectorSize / sizeof(Int16); + + private static SByte[] _data = new SByte[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private SimpleUnaryOpTest__DataTable _dataTable; + + static SimpleUnaryOpTest__ConvertToVector128Int16SByte() + { + 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, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), VectorSize); + } + + public SimpleUnaryOpTest__ConvertToVector128Int16SByte() + { + 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, byte>(ref _fld), ref Unsafe.As(ref _data[0]), VectorSize); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue)); } + _dataTable = new SimpleUnaryOpTest__DataTable(_data, new Int16[RetElementCount], VectorSize); + } + + public bool IsSupported => Sse41.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse41.ConvertToVector128Int16( + Unsafe.Read>(_dataTable.inArrayPtr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse41.ConvertToVector128Int16( + Sse2.LoadVector128((SByte*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse41.ConvertToVector128Int16( + Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.ConvertToVector128Int16), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.ConvertToVector128Int16), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((SByte*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.ConvertToVector128Int16), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse41.ConvertToVector128Int16( + _clsVar + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = Sse41.ConvertToVector128Int16(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var firstOp = Sse2.LoadVector128((SByte*)(_dataTable.inArrayPtr)); + var result = Sse41.ConvertToVector128Int16(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var firstOp = Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArrayPtr)); + var result = Sse41.ConvertToVector128Int16(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleUnaryOpTest__ConvertToVector128Int16SByte(); + var result = Sse41.ConvertToVector128Int16(test._fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse41.ConvertToVector128Int16(_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 firstOp, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray = new SByte[Op1ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(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(ref inArray[0]), ref Unsafe.AsRef(firstOp), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(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(Sse41)}.{nameof(Sse41.ConvertToVector128Int16)}(Vector128): {method} failed:"); + Console.WriteLine($" firstOp: ({string.Join(", ", firstOp)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse41/ConvertToVector128Int32.Byte.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/ConvertToVector128Int32.Byte.cs new file mode 100644 index 000000000000..0b51a421adb0 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/ConvertToVector128Int32.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 ConvertToVector128Int32Byte() + { + var test = new SimpleUnaryOpTest__ConvertToVector128Int32Byte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Sse2.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 (Sse2.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 (Sse2.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__ConvertToVector128Int32Byte + { + private const int VectorSize = 16; + + private const int Op1ElementCount = VectorSize / sizeof(Byte); + private const int RetElementCount = VectorSize / sizeof(Int32); + + private static Byte[] _data = new Byte[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private SimpleUnaryOpTest__DataTable _dataTable; + + static SimpleUnaryOpTest__ConvertToVector128Int32Byte() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (byte)(random.Next(0, byte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), VectorSize); + } + + public SimpleUnaryOpTest__ConvertToVector128Int32Byte() + { + 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, byte>(ref _fld), ref Unsafe.As(ref _data[0]), VectorSize); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (byte)(random.Next(0, byte.MaxValue)); } + _dataTable = new SimpleUnaryOpTest__DataTable(_data, new Int32[RetElementCount], VectorSize); + } + + public bool IsSupported => Sse41.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse41.ConvertToVector128Int32( + Unsafe.Read>(_dataTable.inArrayPtr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse41.ConvertToVector128Int32( + Sse2.LoadVector128((Byte*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse41.ConvertToVector128Int32( + Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.ConvertToVector128Int32), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.ConvertToVector128Int32), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Byte*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.ConvertToVector128Int32), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse41.ConvertToVector128Int32( + _clsVar + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = Sse41.ConvertToVector128Int32(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var firstOp = Sse2.LoadVector128((Byte*)(_dataTable.inArrayPtr)); + var result = Sse41.ConvertToVector128Int32(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var firstOp = Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArrayPtr)); + var result = Sse41.ConvertToVector128Int32(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleUnaryOpTest__ConvertToVector128Int32Byte(); + var result = Sse41.ConvertToVector128Int32(test._fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse41.ConvertToVector128Int32(_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 firstOp, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray = new Byte[Op1ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray = new Byte[Op1ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Byte[] 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(Sse41)}.{nameof(Sse41.ConvertToVector128Int32)}(Vector128): {method} failed:"); + Console.WriteLine($" firstOp: ({string.Join(", ", firstOp)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse41/ConvertToVector128Int32.Int16.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/ConvertToVector128Int32.Int16.cs new file mode 100644 index 000000000000..86a7eaa48deb --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/ConvertToVector128Int32.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 ConvertToVector128Int32Int16() + { + var test = new SimpleUnaryOpTest__ConvertToVector128Int32Int16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Sse2.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 (Sse2.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 (Sse2.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__ConvertToVector128Int32Int16 + { + private const int VectorSize = 16; + + private const int Op1ElementCount = VectorSize / sizeof(Int16); + private const int RetElementCount = VectorSize / sizeof(Int32); + + private static Int16[] _data = new Int16[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private SimpleUnaryOpTest__DataTable _dataTable; + + static SimpleUnaryOpTest__ConvertToVector128Int32Int16() + { + 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, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), VectorSize); + } + + public SimpleUnaryOpTest__ConvertToVector128Int32Int16() + { + 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, byte>(ref _fld), ref Unsafe.As(ref _data[0]), VectorSize); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (short)(random.Next(short.MinValue, short.MaxValue)); } + _dataTable = new SimpleUnaryOpTest__DataTable(_data, new Int32[RetElementCount], VectorSize); + } + + public bool IsSupported => Sse41.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse41.ConvertToVector128Int32( + Unsafe.Read>(_dataTable.inArrayPtr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse41.ConvertToVector128Int32( + Sse2.LoadVector128((Int16*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse41.ConvertToVector128Int32( + Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.ConvertToVector128Int32), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.ConvertToVector128Int32), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Int16*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.ConvertToVector128Int32), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse41.ConvertToVector128Int32( + _clsVar + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = Sse41.ConvertToVector128Int32(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var firstOp = Sse2.LoadVector128((Int16*)(_dataTable.inArrayPtr)); + var result = Sse41.ConvertToVector128Int32(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var firstOp = Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArrayPtr)); + var result = Sse41.ConvertToVector128Int32(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleUnaryOpTest__ConvertToVector128Int32Int16(); + var result = Sse41.ConvertToVector128Int32(test._fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse41.ConvertToVector128Int32(_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 firstOp, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray = new Int16[Op1ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(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(ref inArray[0]), ref Unsafe.AsRef(firstOp), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(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(Sse41)}.{nameof(Sse41.ConvertToVector128Int32)}(Vector128): {method} failed:"); + Console.WriteLine($" firstOp: ({string.Join(", ", firstOp)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse41/ConvertToVector128Int32.SByte.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/ConvertToVector128Int32.SByte.cs new file mode 100644 index 000000000000..43e389b2d4ba --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/ConvertToVector128Int32.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 ConvertToVector128Int32SByte() + { + var test = new SimpleUnaryOpTest__ConvertToVector128Int32SByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Sse2.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 (Sse2.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 (Sse2.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__ConvertToVector128Int32SByte + { + private const int VectorSize = 16; + + private const int Op1ElementCount = VectorSize / sizeof(SByte); + private const int RetElementCount = VectorSize / sizeof(Int32); + + private static SByte[] _data = new SByte[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private SimpleUnaryOpTest__DataTable _dataTable; + + static SimpleUnaryOpTest__ConvertToVector128Int32SByte() + { + 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, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), VectorSize); + } + + public SimpleUnaryOpTest__ConvertToVector128Int32SByte() + { + 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, byte>(ref _fld), ref Unsafe.As(ref _data[0]), VectorSize); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue)); } + _dataTable = new SimpleUnaryOpTest__DataTable(_data, new Int32[RetElementCount], VectorSize); + } + + public bool IsSupported => Sse41.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse41.ConvertToVector128Int32( + Unsafe.Read>(_dataTable.inArrayPtr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse41.ConvertToVector128Int32( + Sse2.LoadVector128((SByte*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse41.ConvertToVector128Int32( + Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.ConvertToVector128Int32), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.ConvertToVector128Int32), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((SByte*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.ConvertToVector128Int32), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse41.ConvertToVector128Int32( + _clsVar + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = Sse41.ConvertToVector128Int32(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var firstOp = Sse2.LoadVector128((SByte*)(_dataTable.inArrayPtr)); + var result = Sse41.ConvertToVector128Int32(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var firstOp = Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArrayPtr)); + var result = Sse41.ConvertToVector128Int32(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleUnaryOpTest__ConvertToVector128Int32SByte(); + var result = Sse41.ConvertToVector128Int32(test._fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse41.ConvertToVector128Int32(_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 firstOp, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray = new SByte[Op1ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(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(ref inArray[0]), ref Unsafe.AsRef(firstOp), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(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(Sse41)}.{nameof(Sse41.ConvertToVector128Int32)}(Vector128): {method} failed:"); + Console.WriteLine($" firstOp: ({string.Join(", ", firstOp)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse41/ConvertToVector128Int32.UInt16.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/ConvertToVector128Int32.UInt16.cs new file mode 100644 index 000000000000..a2ca6846c490 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/ConvertToVector128Int32.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 ConvertToVector128Int32UInt16() + { + var test = new SimpleUnaryOpTest__ConvertToVector128Int32UInt16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Sse2.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 (Sse2.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 (Sse2.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__ConvertToVector128Int32UInt16 + { + private const int VectorSize = 16; + + private const int Op1ElementCount = VectorSize / sizeof(UInt16); + private const int RetElementCount = VectorSize / sizeof(Int32); + + private static UInt16[] _data = new UInt16[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private SimpleUnaryOpTest__DataTable _dataTable; + + static SimpleUnaryOpTest__ConvertToVector128Int32UInt16() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (ushort)(random.Next(0, ushort.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), VectorSize); + } + + public SimpleUnaryOpTest__ConvertToVector128Int32UInt16() + { + 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, byte>(ref _fld), ref Unsafe.As(ref _data[0]), VectorSize); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (ushort)(random.Next(0, ushort.MaxValue)); } + _dataTable = new SimpleUnaryOpTest__DataTable(_data, new Int32[RetElementCount], VectorSize); + } + + public bool IsSupported => Sse41.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse41.ConvertToVector128Int32( + Unsafe.Read>(_dataTable.inArrayPtr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse41.ConvertToVector128Int32( + Sse2.LoadVector128((UInt16*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse41.ConvertToVector128Int32( + Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.ConvertToVector128Int32), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.ConvertToVector128Int32), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((UInt16*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.ConvertToVector128Int32), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse41.ConvertToVector128Int32( + _clsVar + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = Sse41.ConvertToVector128Int32(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var firstOp = Sse2.LoadVector128((UInt16*)(_dataTable.inArrayPtr)); + var result = Sse41.ConvertToVector128Int32(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var firstOp = Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArrayPtr)); + var result = Sse41.ConvertToVector128Int32(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleUnaryOpTest__ConvertToVector128Int32UInt16(); + var result = Sse41.ConvertToVector128Int32(test._fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse41.ConvertToVector128Int32(_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 firstOp, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray = new UInt16[Op1ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray = new UInt16[Op1ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(UInt16[] 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(Sse41)}.{nameof(Sse41.ConvertToVector128Int32)}(Vector128): {method} failed:"); + Console.WriteLine($" firstOp: ({string.Join(", ", firstOp)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse41/ConvertToVector128Int64.Byte.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/ConvertToVector128Int64.Byte.cs new file mode 100644 index 000000000000..0e51ba138d7a --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/ConvertToVector128Int64.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 ConvertToVector128Int64Byte() + { + var test = new SimpleUnaryOpTest__ConvertToVector128Int64Byte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Sse2.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 (Sse2.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 (Sse2.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__ConvertToVector128Int64Byte + { + private const int VectorSize = 16; + + private const int Op1ElementCount = VectorSize / sizeof(Byte); + private const int RetElementCount = VectorSize / sizeof(Int64); + + private static Byte[] _data = new Byte[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private SimpleUnaryOpTest__DataTable _dataTable; + + static SimpleUnaryOpTest__ConvertToVector128Int64Byte() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (byte)(random.Next(0, byte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), VectorSize); + } + + public SimpleUnaryOpTest__ConvertToVector128Int64Byte() + { + 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, byte>(ref _fld), ref Unsafe.As(ref _data[0]), VectorSize); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (byte)(random.Next(0, byte.MaxValue)); } + _dataTable = new SimpleUnaryOpTest__DataTable(_data, new Int64[RetElementCount], VectorSize); + } + + public bool IsSupported => Sse41.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse41.ConvertToVector128Int64( + Unsafe.Read>(_dataTable.inArrayPtr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse41.ConvertToVector128Int64( + Sse2.LoadVector128((Byte*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse41.ConvertToVector128Int64( + Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.ConvertToVector128Int64), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.ConvertToVector128Int64), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Byte*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.ConvertToVector128Int64), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse41.ConvertToVector128Int64( + _clsVar + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = Sse41.ConvertToVector128Int64(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var firstOp = Sse2.LoadVector128((Byte*)(_dataTable.inArrayPtr)); + var result = Sse41.ConvertToVector128Int64(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var firstOp = Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArrayPtr)); + var result = Sse41.ConvertToVector128Int64(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleUnaryOpTest__ConvertToVector128Int64Byte(); + var result = Sse41.ConvertToVector128Int64(test._fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse41.ConvertToVector128Int64(_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 firstOp, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray = new Byte[Op1ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray = new Byte[Op1ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Byte[] 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(Sse41)}.{nameof(Sse41.ConvertToVector128Int64)}(Vector128): {method} failed:"); + Console.WriteLine($" firstOp: ({string.Join(", ", firstOp)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse41/ConvertToVector128Int64.Int16.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/ConvertToVector128Int64.Int16.cs new file mode 100644 index 000000000000..b631e925322f --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/ConvertToVector128Int64.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 ConvertToVector128Int64Int16() + { + var test = new SimpleUnaryOpTest__ConvertToVector128Int64Int16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Sse2.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 (Sse2.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 (Sse2.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__ConvertToVector128Int64Int16 + { + private const int VectorSize = 16; + + private const int Op1ElementCount = VectorSize / sizeof(Int16); + private const int RetElementCount = VectorSize / sizeof(Int64); + + private static Int16[] _data = new Int16[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private SimpleUnaryOpTest__DataTable _dataTable; + + static SimpleUnaryOpTest__ConvertToVector128Int64Int16() + { + 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, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), VectorSize); + } + + public SimpleUnaryOpTest__ConvertToVector128Int64Int16() + { + 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, byte>(ref _fld), ref Unsafe.As(ref _data[0]), VectorSize); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (short)(random.Next(short.MinValue, short.MaxValue)); } + _dataTable = new SimpleUnaryOpTest__DataTable(_data, new Int64[RetElementCount], VectorSize); + } + + public bool IsSupported => Sse41.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse41.ConvertToVector128Int64( + Unsafe.Read>(_dataTable.inArrayPtr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse41.ConvertToVector128Int64( + Sse2.LoadVector128((Int16*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse41.ConvertToVector128Int64( + Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.ConvertToVector128Int64), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.ConvertToVector128Int64), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Int16*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.ConvertToVector128Int64), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse41.ConvertToVector128Int64( + _clsVar + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = Sse41.ConvertToVector128Int64(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var firstOp = Sse2.LoadVector128((Int16*)(_dataTable.inArrayPtr)); + var result = Sse41.ConvertToVector128Int64(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var firstOp = Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArrayPtr)); + var result = Sse41.ConvertToVector128Int64(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleUnaryOpTest__ConvertToVector128Int64Int16(); + var result = Sse41.ConvertToVector128Int64(test._fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse41.ConvertToVector128Int64(_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 firstOp, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray = new Int16[Op1ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(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(ref inArray[0]), ref Unsafe.AsRef(firstOp), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(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(Sse41)}.{nameof(Sse41.ConvertToVector128Int64)}(Vector128): {method} failed:"); + Console.WriteLine($" firstOp: ({string.Join(", ", firstOp)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse41/ConvertToVector128Int64.Int32.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/ConvertToVector128Int64.Int32.cs new file mode 100644 index 000000000000..34e5d0289046 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/ConvertToVector128Int64.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 ConvertToVector128Int64Int32() + { + var test = new SimpleUnaryOpTest__ConvertToVector128Int64Int32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Sse2.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 (Sse2.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 (Sse2.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__ConvertToVector128Int64Int32 + { + private const int VectorSize = 16; + + private const int Op1ElementCount = VectorSize / sizeof(Int32); + private const int RetElementCount = VectorSize / sizeof(Int64); + + private static Int32[] _data = new Int32[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private SimpleUnaryOpTest__DataTable _dataTable; + + static SimpleUnaryOpTest__ConvertToVector128Int64Int32() + { + 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, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), VectorSize); + } + + public SimpleUnaryOpTest__ConvertToVector128Int64Int32() + { + 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, byte>(ref _fld), ref Unsafe.As(ref _data[0]), VectorSize); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (int)(random.Next(int.MinValue, int.MaxValue)); } + _dataTable = new SimpleUnaryOpTest__DataTable(_data, new Int64[RetElementCount], VectorSize); + } + + public bool IsSupported => Sse41.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse41.ConvertToVector128Int64( + Unsafe.Read>(_dataTable.inArrayPtr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse41.ConvertToVector128Int64( + Sse2.LoadVector128((Int32*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse41.ConvertToVector128Int64( + Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.ConvertToVector128Int64), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.ConvertToVector128Int64), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Int32*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.ConvertToVector128Int64), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse41.ConvertToVector128Int64( + _clsVar + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = Sse41.ConvertToVector128Int64(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var firstOp = Sse2.LoadVector128((Int32*)(_dataTable.inArrayPtr)); + var result = Sse41.ConvertToVector128Int64(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var firstOp = Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArrayPtr)); + var result = Sse41.ConvertToVector128Int64(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleUnaryOpTest__ConvertToVector128Int64Int32(); + var result = Sse41.ConvertToVector128Int64(test._fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse41.ConvertToVector128Int64(_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 firstOp, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray = new Int32[Op1ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(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(ref inArray[0]), ref Unsafe.AsRef(firstOp), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(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(Sse41)}.{nameof(Sse41.ConvertToVector128Int64)}(Vector128): {method} failed:"); + Console.WriteLine($" firstOp: ({string.Join(", ", firstOp)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse41/ConvertToVector128Int64.SByte.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/ConvertToVector128Int64.SByte.cs new file mode 100644 index 000000000000..519070152a4a --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/ConvertToVector128Int64.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 ConvertToVector128Int64SByte() + { + var test = new SimpleUnaryOpTest__ConvertToVector128Int64SByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Sse2.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 (Sse2.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 (Sse2.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__ConvertToVector128Int64SByte + { + private const int VectorSize = 16; + + private const int Op1ElementCount = VectorSize / sizeof(SByte); + private const int RetElementCount = VectorSize / sizeof(Int64); + + private static SByte[] _data = new SByte[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private SimpleUnaryOpTest__DataTable _dataTable; + + static SimpleUnaryOpTest__ConvertToVector128Int64SByte() + { + 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, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), VectorSize); + } + + public SimpleUnaryOpTest__ConvertToVector128Int64SByte() + { + 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, byte>(ref _fld), ref Unsafe.As(ref _data[0]), VectorSize); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue)); } + _dataTable = new SimpleUnaryOpTest__DataTable(_data, new Int64[RetElementCount], VectorSize); + } + + public bool IsSupported => Sse41.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse41.ConvertToVector128Int64( + Unsafe.Read>(_dataTable.inArrayPtr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse41.ConvertToVector128Int64( + Sse2.LoadVector128((SByte*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse41.ConvertToVector128Int64( + Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.ConvertToVector128Int64), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.ConvertToVector128Int64), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((SByte*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.ConvertToVector128Int64), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse41.ConvertToVector128Int64( + _clsVar + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = Sse41.ConvertToVector128Int64(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var firstOp = Sse2.LoadVector128((SByte*)(_dataTable.inArrayPtr)); + var result = Sse41.ConvertToVector128Int64(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var firstOp = Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArrayPtr)); + var result = Sse41.ConvertToVector128Int64(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleUnaryOpTest__ConvertToVector128Int64SByte(); + var result = Sse41.ConvertToVector128Int64(test._fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse41.ConvertToVector128Int64(_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 firstOp, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray = new SByte[Op1ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(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(ref inArray[0]), ref Unsafe.AsRef(firstOp), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(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(Sse41)}.{nameof(Sse41.ConvertToVector128Int64)}(Vector128): {method} failed:"); + Console.WriteLine($" firstOp: ({string.Join(", ", firstOp)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse41/ConvertToVector128Int64.UInt16.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/ConvertToVector128Int64.UInt16.cs new file mode 100644 index 000000000000..afb456fd2433 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/ConvertToVector128Int64.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 ConvertToVector128Int64UInt16() + { + var test = new SimpleUnaryOpTest__ConvertToVector128Int64UInt16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Sse2.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 (Sse2.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 (Sse2.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__ConvertToVector128Int64UInt16 + { + private const int VectorSize = 16; + + private const int Op1ElementCount = VectorSize / sizeof(UInt16); + private const int RetElementCount = VectorSize / sizeof(Int64); + + private static UInt16[] _data = new UInt16[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private SimpleUnaryOpTest__DataTable _dataTable; + + static SimpleUnaryOpTest__ConvertToVector128Int64UInt16() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (ushort)(random.Next(0, ushort.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), VectorSize); + } + + public SimpleUnaryOpTest__ConvertToVector128Int64UInt16() + { + 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, byte>(ref _fld), ref Unsafe.As(ref _data[0]), VectorSize); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (ushort)(random.Next(0, ushort.MaxValue)); } + _dataTable = new SimpleUnaryOpTest__DataTable(_data, new Int64[RetElementCount], VectorSize); + } + + public bool IsSupported => Sse41.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse41.ConvertToVector128Int64( + Unsafe.Read>(_dataTable.inArrayPtr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse41.ConvertToVector128Int64( + Sse2.LoadVector128((UInt16*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse41.ConvertToVector128Int64( + Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.ConvertToVector128Int64), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.ConvertToVector128Int64), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((UInt16*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.ConvertToVector128Int64), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse41.ConvertToVector128Int64( + _clsVar + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = Sse41.ConvertToVector128Int64(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var firstOp = Sse2.LoadVector128((UInt16*)(_dataTable.inArrayPtr)); + var result = Sse41.ConvertToVector128Int64(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var firstOp = Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArrayPtr)); + var result = Sse41.ConvertToVector128Int64(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleUnaryOpTest__ConvertToVector128Int64UInt16(); + var result = Sse41.ConvertToVector128Int64(test._fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse41.ConvertToVector128Int64(_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 firstOp, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray = new UInt16[Op1ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray = new UInt16[Op1ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(UInt16[] 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(Sse41)}.{nameof(Sse41.ConvertToVector128Int64)}(Vector128): {method} failed:"); + Console.WriteLine($" firstOp: ({string.Join(", ", firstOp)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse41/ConvertToVector128Int64.UInt32.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/ConvertToVector128Int64.UInt32.cs new file mode 100644 index 000000000000..5eb6e4e693b6 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/ConvertToVector128Int64.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 ConvertToVector128Int64UInt32() + { + var test = new SimpleUnaryOpTest__ConvertToVector128Int64UInt32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Sse2.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 (Sse2.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 (Sse2.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__ConvertToVector128Int64UInt32 + { + private const int VectorSize = 16; + + private const int Op1ElementCount = VectorSize / sizeof(UInt32); + private const int RetElementCount = VectorSize / sizeof(Int64); + + private static UInt32[] _data = new UInt32[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private SimpleUnaryOpTest__DataTable _dataTable; + + static SimpleUnaryOpTest__ConvertToVector128Int64UInt32() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (uint)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), VectorSize); + } + + public SimpleUnaryOpTest__ConvertToVector128Int64UInt32() + { + 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, byte>(ref _fld), ref Unsafe.As(ref _data[0]), VectorSize); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (uint)(random.Next(0, int.MaxValue)); } + _dataTable = new SimpleUnaryOpTest__DataTable(_data, new Int64[RetElementCount], VectorSize); + } + + public bool IsSupported => Sse41.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse41.ConvertToVector128Int64( + Unsafe.Read>(_dataTable.inArrayPtr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse41.ConvertToVector128Int64( + Sse2.LoadVector128((UInt32*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse41.ConvertToVector128Int64( + Sse2.LoadAlignedVector128((UInt32*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.ConvertToVector128Int64), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.ConvertToVector128Int64), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((UInt32*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.ConvertToVector128Int64), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((UInt32*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse41.ConvertToVector128Int64( + _clsVar + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = Sse41.ConvertToVector128Int64(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var firstOp = Sse2.LoadVector128((UInt32*)(_dataTable.inArrayPtr)); + var result = Sse41.ConvertToVector128Int64(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var firstOp = Sse2.LoadAlignedVector128((UInt32*)(_dataTable.inArrayPtr)); + var result = Sse41.ConvertToVector128Int64(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleUnaryOpTest__ConvertToVector128Int64UInt32(); + var result = Sse41.ConvertToVector128Int64(test._fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse41.ConvertToVector128Int64(_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 firstOp, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray = new UInt32[Op1ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray = new UInt32[Op1ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(UInt32[] 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(Sse41)}.{nameof(Sse41.ConvertToVector128Int64)}(Vector128): {method} failed:"); + Console.WriteLine($" firstOp: ({string.Join(", ", firstOp)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse41/ConvertToVector128_r.csproj b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/ConvertToVector128_r.csproj new file mode 100644 index 000000000000..184a0f693f4e --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/ConvertToVector128_r.csproj @@ -0,0 +1,48 @@ + + + + + Debug + AnyCPU + 2.0 + {95DFC527-4DC1-495E-97D7-E94EE1F7140D} + Exe + {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + ..\..\ + true + + + + + + + False + + + + None + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse41/ConvertToVector128_ro.csproj b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/ConvertToVector128_ro.csproj new file mode 100644 index 000000000000..7e588cb2ce9c --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/ConvertToVector128_ro.csproj @@ -0,0 +1,48 @@ + + + + + Debug + AnyCPU + 2.0 + {95DFC527-4DC1-495E-97D7-E94EE1F7140D} + Exe + {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + ..\..\ + true + + + + + + + False + + + + None + True + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse41/DotProduct.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/DotProduct.cs new file mode 100644 index 000000000000..096c6cce6491 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/DotProduct.cs @@ -0,0 +1,225 @@ +// 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.Linq; +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 (Sse41.IsSupported) + { + using (TestTable floatTable = new TestTable(new float[4] { 1, -5, 100, 0 }, new float[4] { 22, -1, -50, 0 }, new float[4])) + { + var vf1 = Unsafe.Read>(floatTable.inArray1Ptr); + var vf2 = Unsafe.Read>(floatTable.inArray2Ptr); + + var vf3 = Sse41.DotProduct(vf1, vf2, 255); + Unsafe.Write(floatTable.outArrayPtr, vf3); + + if (!floatTable.CheckResult((x, y, z) => z.All(result => result == (x[0] * y[0]) + (x[1] * y[1]) + + (x[2] * y[2]) + (x[3] * y[3])))) + { + Console.WriteLine("SSE41 DotProduct failed on float:"); + foreach (var item in floatTable.outArray) + { + Console.Write(item + ", "); + } + Console.WriteLine(); + testResult = Fail; + } + + vf3 = Sse41.DotProduct(vf1, vf2, 127); + Unsafe.Write(floatTable.outArrayPtr, vf3); + + if (!floatTable.CheckResult((x, y, z) => z.All(result => result == (x[0] * y[0]) + (x[1] * y[1]) + + (x[2] * y[2])))) + { + Console.WriteLine("SSE41 DotProduct failed on float:"); + foreach (var item in floatTable.outArray) + { + Console.Write(item + ", "); + } + Console.WriteLine(); + testResult = Fail; + } + + vf3 = Sse41.DotProduct(vf1, vf2, 63); + Unsafe.Write(floatTable.outArrayPtr, vf3); + + if (!floatTable.CheckResult((x, y, z) => z.All(result => result == ((x[0] * y[0]) + (x[1] * y[1]))))) + { + Console.WriteLine("3 SSE41 DotProduct failed on float:"); + foreach (var item in floatTable.outArray) + { + Console.Write(item + ", "); + } + Console.WriteLine(); + testResult = Fail; + } + + vf3 = Sse41.DotProduct(vf1, vf2, 85); + Unsafe.Write(floatTable.outArrayPtr, vf3); + + if (!floatTable.CheckResult((x, y, z) => z[0] == ((x[0] * y[0]) + (x[2] * y[2])) && + z[2] == ((x[0] * y[0]) + (x[2] * y[2])) && + z[1] == 0 && z[3] == 0)) + { + Console.WriteLine("SSE41 DotProduct failed on float:"); + foreach (var item in floatTable.outArray) + { + Console.Write(item + ", "); + } + Console.WriteLine(); + testResult = Fail; + } + + vf3 = (Vector128)typeof(Sse41).GetMethod(nameof(Sse41.DotProduct), new Type[] { vf1.GetType(), vf2.GetType(), typeof(byte) }).Invoke(null, new object[] { vf1, vf2, (byte)(255) }); + Unsafe.Write(floatTable.outArrayPtr, vf3); + + if (!floatTable.CheckResult((x, y, z) => z.All(result => result == (x[0] * y[0]) + (x[1] * y[1]) + + (x[2] * y[2]) + (x[3] * y[3])))) + { + Console.WriteLine("SSE41 DotProduct failed on float:"); + foreach (var item in floatTable.outArray) + { + Console.Write(item + ", "); + } + Console.WriteLine(); + testResult = Fail; + } + } + + using (TestTable doubleTable = new TestTable(new double[2] { 1, -5 }, new double[2] { 22, -1 }, new double[2])) + { + var vf1 = Unsafe.Read>(doubleTable.inArray1Ptr); + var vf2 = Unsafe.Read>(doubleTable.inArray2Ptr); + + var vf3 = Sse41.DotProduct(vf1, vf2, 51); + Unsafe.Write(doubleTable.outArrayPtr, vf3); + + if (!doubleTable.CheckResult((x, y, z) => z.All(result => result == (x[0] * y[0]) + (x[1] * y[1])))) + { + Console.WriteLine("SSE41 DotProduct failed on double:"); + foreach (var item in doubleTable.outArray) + { + Console.Write(item + ", "); + } + Console.WriteLine(); + testResult = Fail; + } + + vf3 = Sse41.DotProduct(vf1, vf2, 19); + Unsafe.Write(doubleTable.outArrayPtr, vf3); + + if (!doubleTable.CheckResult((x, y, z) => z.All(result => result == (x[0] * y[0])))) + { + Console.WriteLine("SSE41 DotProduct failed on double:"); + foreach (var item in doubleTable.outArray) + { + Console.Write(item + ", "); + } + Console.WriteLine(); + testResult = Fail; + } + + vf3 = Sse41.DotProduct(vf1, vf2, 17); + Unsafe.Write(doubleTable.outArrayPtr, vf3); + + if (!doubleTable.CheckResult((x, y, z) => z[0] == (x[0] * y[0]) && + z[1] == 0)) + { + Console.WriteLine("SSE41 DotProduct failed on double:"); + foreach (var item in doubleTable.outArray) + { + Console.Write(item + ", "); + } + Console.WriteLine(); + testResult = Fail; + } + + vf3 = Sse41.DotProduct(vf1, vf2, 33); + Unsafe.Write(doubleTable.outArrayPtr, vf3); + + if (!doubleTable.CheckResult((x, y, z) => z[0] == (x[1] * y[1]) && + z[1] == 0)) + { + Console.WriteLine("SSE41 DotProduct failed on double:"); + foreach (var item in doubleTable.outArray) + { + Console.Write(item + ", "); + } + Console.WriteLine(); + testResult = Fail; + } + + vf3 = (Vector128)typeof(Sse41).GetMethod(nameof(Sse41.DotProduct), new Type[] { vf1.GetType(), vf2.GetType(), typeof(byte) }).Invoke(null, new object[] { vf1, vf2, (byte)(51) }); + Unsafe.Write(doubleTable.outArrayPtr, vf3); + + if (!doubleTable.CheckResult((x, y, z) => z.All(result => result == (x[0] * y[0]) + (x[1] * y[1])))) + { + Console.WriteLine("SSE41 DotProduct failed on double:"); + foreach (var item in doubleTable.outArray) + { + Console.Write(item + ", "); + } + Console.WriteLine(); + testResult = Fail; + } + } + } + + return testResult; + } + + public unsafe struct TestTable : IDisposable where T : struct + { + public T[] inArray1; + public T[] inArray2; + public T[] outArray; + + public void* inArray1Ptr => inHandle1.AddrOfPinnedObject().ToPointer(); + public void* inArray2Ptr => inHandle2.AddrOfPinnedObject().ToPointer(); + public void* outArrayPtr => outHandle.AddrOfPinnedObject().ToPointer(); + + GCHandle inHandle1; + GCHandle inHandle2; + GCHandle outHandle; + public TestTable(T[] a, T[] b, T[] c) + { + this.inArray1 = a; + this.inArray2 = b; + this.outArray = c; + + inHandle1 = GCHandle.Alloc(inArray1, GCHandleType.Pinned); + inHandle2 = GCHandle.Alloc(inArray2, GCHandleType.Pinned); + outHandle = GCHandle.Alloc(outArray, GCHandleType.Pinned); + } + public bool CheckResult(Func check) + { + return check(inArray1, inArray2, outArray); + } + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse41/DotProduct_r.csproj b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/DotProduct_r.csproj new file mode 100644 index 000000000000..59f4aa55ed98 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/DotProduct_r.csproj @@ -0,0 +1,34 @@ + + + + + Debug + AnyCPU + 2.0 + {95DFC527-4DC1-495E-97D7-E94EE1F7140D} + Exe + {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + ..\..\ + true + + + + + + + False + + + + None + + + + + + + + + + + diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse41/DotProduct_ro.csproj b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/DotProduct_ro.csproj new file mode 100644 index 000000000000..9b8e5c4c9265 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/DotProduct_ro.csproj @@ -0,0 +1,34 @@ + + + + + Debug + AnyCPU + 2.0 + {95DFC527-4DC1-495E-97D7-E94EE1F7140D} + Exe + {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + ..\..\ + true + + + + + + + False + + + + None + True + + + + + + + + + + diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse41/Floor.Double.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/Floor.Double.cs new file mode 100644 index 000000000000..f2325436ff75 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/Floor.Double.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 FloorDouble() + { + var test = new SimpleUnaryOpTest__FloorDouble(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Sse2.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 (Sse2.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 (Sse2.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__FloorDouble + { + private const int VectorSize = 16; + + private const int Op1ElementCount = VectorSize / sizeof(Double); + private const int RetElementCount = VectorSize / sizeof(Double); + + private static Double[] _data = new Double[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private SimpleUnaryOpTest__DataTable _dataTable; + + static SimpleUnaryOpTest__FloorDouble() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (double)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), VectorSize); + } + + public SimpleUnaryOpTest__FloorDouble() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (double)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), VectorSize); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (double)(random.NextDouble()); } + _dataTable = new SimpleUnaryOpTest__DataTable(_data, new Double[RetElementCount], VectorSize); + } + + public bool IsSupported => Sse41.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse41.Floor( + Unsafe.Read>(_dataTable.inArrayPtr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse41.Floor( + Sse2.LoadVector128((Double*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse41.Floor( + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.Floor), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.Floor), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Double*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.Floor), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse41.Floor( + _clsVar + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = Sse41.Floor(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var firstOp = Sse2.LoadVector128((Double*)(_dataTable.inArrayPtr)); + var result = Sse41.Floor(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var firstOp = Sse2.LoadAlignedVector128((Double*)(_dataTable.inArrayPtr)); + var result = Sse41.Floor(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleUnaryOpTest__FloorDouble(); + var result = Sse41.Floor(test._fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse41.Floor(_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 firstOp, void* result, [CallerMemberName] string method = "") + { + Double[] inArray = new Double[Op1ElementCount]; + Double[] outArray = new Double[RetElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Double[] inArray = new Double[Op1ElementCount]; + Double[] outArray = new Double[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Double[] firstOp, Double[] result, [CallerMemberName] string method = "") + { + if (BitConverter.DoubleToInt64Bits(result[0]) != BitConverter.DoubleToInt64Bits(Math.Floor(firstOp[0]))) + { + Succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (BitConverter.DoubleToInt64Bits(result[i]) != BitConverter.DoubleToInt64Bits(Math.Floor(firstOp[i]))) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Sse41)}.{nameof(Sse41.Floor)}(Vector128): {method} failed:"); + Console.WriteLine($" firstOp: ({string.Join(", ", firstOp)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse41/Floor.Single.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/Floor.Single.cs new file mode 100644 index 000000000000..19d2d55e9165 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/Floor.Single.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 FloorSingle() + { + var test = new SimpleUnaryOpTest__FloorSingle(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Sse.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 (Sse.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 (Sse.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__FloorSingle + { + private const int VectorSize = 16; + + private const int Op1ElementCount = VectorSize / sizeof(Single); + private const int RetElementCount = VectorSize / sizeof(Single); + + private static Single[] _data = new Single[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private SimpleUnaryOpTest__DataTable _dataTable; + + static SimpleUnaryOpTest__FloorSingle() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (float)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), VectorSize); + } + + public SimpleUnaryOpTest__FloorSingle() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (float)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), VectorSize); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (float)(random.NextDouble()); } + _dataTable = new SimpleUnaryOpTest__DataTable(_data, new Single[RetElementCount], VectorSize); + } + + public bool IsSupported => Sse41.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse41.Floor( + Unsafe.Read>(_dataTable.inArrayPtr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse41.Floor( + Sse.LoadVector128((Single*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse41.Floor( + Sse.LoadAlignedVector128((Single*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.Floor), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.Floor), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadVector128((Single*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.Floor), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadAlignedVector128((Single*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse41.Floor( + _clsVar + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = Sse41.Floor(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var firstOp = Sse.LoadVector128((Single*)(_dataTable.inArrayPtr)); + var result = Sse41.Floor(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var firstOp = Sse.LoadAlignedVector128((Single*)(_dataTable.inArrayPtr)); + var result = Sse41.Floor(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleUnaryOpTest__FloorSingle(); + var result = Sse41.Floor(test._fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse41.Floor(_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 firstOp, void* result, [CallerMemberName] string method = "") + { + Single[] inArray = new Single[Op1ElementCount]; + Single[] outArray = new Single[RetElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Single[] inArray = new Single[Op1ElementCount]; + Single[] outArray = new Single[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Single[] firstOp, Single[] result, [CallerMemberName] string method = "") + { + if (BitConverter.SingleToInt32Bits(result[0]) != BitConverter.SingleToInt32Bits(MathF.Floor(firstOp[0]))) + { + Succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (BitConverter.SingleToInt32Bits(result[i]) != BitConverter.SingleToInt32Bits(MathF.Floor(firstOp[i]))) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Sse41)}.{nameof(Sse41.Floor)}(Vector128): {method} failed:"); + Console.WriteLine($" firstOp: ({string.Join(", ", firstOp)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse41/FloorScalar.Double.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/FloorScalar.Double.cs new file mode 100644 index 000000000000..6de23a87405c --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/FloorScalar.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 FloorScalarDouble() + { + var test = new SimpleBinaryOpTest__FloorScalarDouble(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Sse2.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 (Sse2.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 (Sse2.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__FloorScalarDouble + { + private const int VectorSize = 16; + + 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 Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private SimpleBinaryOpTest__DataTable _dataTable; + + static SimpleBinaryOpTest__FloorScalarDouble() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (double)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (double)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), VectorSize); + } + + public SimpleBinaryOpTest__FloorScalarDouble() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (double)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (double)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(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(_data1, _data2, new Double[RetElementCount], VectorSize); + } + + public bool IsSupported => Sse41.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse41.FloorScalar( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse41.FloorScalar( + Sse2.LoadVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Double*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse41.FloorScalar( + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.FloorScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.FloorScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Double*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.FloorScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse41.FloorScalar( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read>(_dataTable.inArray1Ptr); + var right = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = Sse41.FloorScalar(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((Double*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((Double*)(_dataTable.inArray2Ptr)); + var result = Sse41.FloorScalar(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray2Ptr)); + var result = Sse41.FloorScalar(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__FloorScalarDouble(); + var result = Sse41.FloorScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse41.FloorScalar(_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(Vector128 left, Vector128 right, void* result, [CallerMemberName] string method = "") + { + Double[] inArray1 = new Double[Op1ElementCount]; + Double[] inArray2 = new Double[Op2ElementCount]; + Double[] outArray = new Double[RetElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(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(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(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(Math.Floor(right[0]))) + { + Succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (BitConverter.DoubleToInt64Bits(result[i]) != BitConverter.DoubleToInt64Bits(left[i])) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Sse41)}.{nameof(Sse41.FloorScalar)}(Vector128, Vector128): {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/Sse41/FloorScalar.Single.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/FloorScalar.Single.cs new file mode 100644 index 000000000000..2b3d9f0d3513 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/FloorScalar.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 FloorScalarSingle() + { + var test = new SimpleBinaryOpTest__FloorScalarSingle(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Sse.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 (Sse.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 (Sse.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__FloorScalarSingle + { + private const int VectorSize = 16; + + 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 Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private SimpleBinaryOpTest__DataTable _dataTable; + + static SimpleBinaryOpTest__FloorScalarSingle() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (float)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (float)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), VectorSize); + } + + public SimpleBinaryOpTest__FloorScalarSingle() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (float)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (float)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(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(_data1, _data2, new Single[RetElementCount], VectorSize); + } + + public bool IsSupported => Sse41.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse41.FloorScalar( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse41.FloorScalar( + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse41.FloorScalar( + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.FloorScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.FloorScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.FloorScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse41.FloorScalar( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read>(_dataTable.inArray1Ptr); + var right = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = Sse41.FloorScalar(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse41.FloorScalar(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse41.FloorScalar(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__FloorScalarSingle(); + var result = Sse41.FloorScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse41.FloorScalar(_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(Vector128 left, Vector128 right, void* result, [CallerMemberName] string method = "") + { + Single[] inArray1 = new Single[Op1ElementCount]; + Single[] inArray2 = new Single[Op2ElementCount]; + Single[] outArray = new Single[RetElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(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(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(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(MathF.Floor(right[0]))) + { + Succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (BitConverter.SingleToInt32Bits(result[i]) != BitConverter.SingleToInt32Bits(left[i])) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Sse41)}.{nameof(Sse41.FloorScalar)}(Vector128, Vector128): {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/Sse41/Max.Int32.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/Max.Int32.cs new file mode 100644 index 000000000000..a96260b5309c --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/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 (Sse2.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 (Sse2.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 (Sse2.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 const int VectorSize = 16; + + 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 Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private SimpleBinaryOpTest__DataTable _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, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (int)(random.Next(int.MinValue, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), VectorSize); + } + + 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, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (int)(random.Next(int.MinValue, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), VectorSize); + + 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(_data1, _data2, new Int32[RetElementCount], VectorSize); + } + + public bool IsSupported => Sse41.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse41.Max( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse41.Max( + Sse2.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Int32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse41.Max( + Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.Max), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.Max), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Int32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.Max), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse41.Max( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read>(_dataTable.inArray1Ptr); + var right = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = Sse41.Max(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((Int32*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((Int32*)(_dataTable.inArray2Ptr)); + var result = Sse41.Max(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray2Ptr)); + var result = Sse41.Max(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__MaxInt32(); + var result = Sse41.Max(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse41.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(Vector128 left, Vector128 right, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(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(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); + + 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(Sse41)}.{nameof(Sse41.Max)}(Vector128, Vector128): {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/Sse41/Max.SByte.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/Max.SByte.cs new file mode 100644 index 000000000000..9dd962dedd17 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/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 (Sse2.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 (Sse2.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 (Sse2.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 const int VectorSize = 16; + + private const int Op1ElementCount = VectorSize / sizeof(SByte); + private const int Op2ElementCount = VectorSize / sizeof(SByte); + private const int RetElementCount = VectorSize / sizeof(SByte); + + private static SByte[] _data1 = new SByte[Op1ElementCount]; + private static SByte[] _data2 = new SByte[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private SimpleBinaryOpTest__DataTable _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, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), VectorSize); + } + + 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, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), VectorSize); + + 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(_data1, _data2, new SByte[RetElementCount], VectorSize); + } + + public bool IsSupported => Sse41.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse41.Max( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse41.Max( + Sse2.LoadVector128((SByte*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((SByte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse41.Max( + Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.Max), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.Max), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((SByte*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((SByte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.Max), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse41.Max( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read>(_dataTable.inArray1Ptr); + var right = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = Sse41.Max(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((SByte*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((SByte*)(_dataTable.inArray2Ptr)); + var result = Sse41.Max(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArray2Ptr)); + var result = Sse41.Max(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__MaxSByte(); + var result = Sse41.Max(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse41.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(Vector128 left, Vector128 right, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); + + 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(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); + + 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(Sse41)}.{nameof(Sse41.Max)}(Vector128, Vector128): {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/Sse41/Max.UInt16.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/Max.UInt16.cs new file mode 100644 index 000000000000..60160a891516 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/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 (Sse2.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 (Sse2.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 (Sse2.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 const int VectorSize = 16; + + private const int Op1ElementCount = VectorSize / sizeof(UInt16); + private const int Op2ElementCount = VectorSize / sizeof(UInt16); + private const int RetElementCount = VectorSize / sizeof(UInt16); + + private static UInt16[] _data1 = new UInt16[Op1ElementCount]; + private static UInt16[] _data2 = new UInt16[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private SimpleBinaryOpTest__DataTable _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, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (ushort)(random.Next(0, ushort.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), VectorSize); + } + + 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, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (ushort)(random.Next(0, ushort.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), VectorSize); + + 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(_data1, _data2, new UInt16[RetElementCount], VectorSize); + } + + public bool IsSupported => Sse41.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse41.Max( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse41.Max( + Sse2.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse41.Max( + Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.Max), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.Max), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.Max), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse41.Max( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read>(_dataTable.inArray1Ptr); + var right = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = Sse41.Max(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)); + var result = Sse41.Max(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArray2Ptr)); + var result = Sse41.Max(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__MaxUInt16(); + var result = Sse41.Max(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse41.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(Vector128 left, Vector128 right, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); + + 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(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); + + 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(Sse41)}.{nameof(Sse41.Max)}(Vector128, Vector128): {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/Sse41/Max.UInt32.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/Max.UInt32.cs new file mode 100644 index 000000000000..cf9b9cc844c9 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/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 (Sse2.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 (Sse2.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 (Sse2.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 const int VectorSize = 16; + + 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 Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private SimpleBinaryOpTest__DataTable _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, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (uint)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), VectorSize); + } + + 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, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (uint)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(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(_data1, _data2, new UInt32[RetElementCount], VectorSize); + } + + public bool IsSupported => Sse41.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse41.Max( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse41.Max( + Sse2.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse41.Max( + Sse2.LoadAlignedVector128((UInt32*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((UInt32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.Max), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.Max), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.Max), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((UInt32*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((UInt32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse41.Max( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read>(_dataTable.inArray1Ptr); + var right = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = Sse41.Max(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)); + var result = Sse41.Max(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((UInt32*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((UInt32*)(_dataTable.inArray2Ptr)); + var result = Sse41.Max(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__MaxUInt32(); + var result = Sse41.Max(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse41.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(Vector128 left, Vector128 right, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(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(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); + + 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(Sse41)}.{nameof(Sse41.Max)}(Vector128, Vector128): {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/Sse41/Min.Int32.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/Min.Int32.cs new file mode 100644 index 000000000000..df30b2ac8242 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/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 (Sse2.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 (Sse2.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 (Sse2.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 const int VectorSize = 16; + + 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 Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private SimpleBinaryOpTest__DataTable _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, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (int)(random.Next(int.MinValue, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), VectorSize); + } + + 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, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (int)(random.Next(int.MinValue, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), VectorSize); + + 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(_data1, _data2, new Int32[RetElementCount], VectorSize); + } + + public bool IsSupported => Sse41.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse41.Min( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse41.Min( + Sse2.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Int32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse41.Min( + Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.Min), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.Min), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Int32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.Min), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse41.Min( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read>(_dataTable.inArray1Ptr); + var right = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = Sse41.Min(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((Int32*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((Int32*)(_dataTable.inArray2Ptr)); + var result = Sse41.Min(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray2Ptr)); + var result = Sse41.Min(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__MinInt32(); + var result = Sse41.Min(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse41.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(Vector128 left, Vector128 right, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(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(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); + + 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(Sse41)}.{nameof(Sse41.Min)}(Vector128, Vector128): {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/Sse41/Min.SByte.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/Min.SByte.cs new file mode 100644 index 000000000000..d7186fd7eab5 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/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 (Sse2.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 (Sse2.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 (Sse2.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 const int VectorSize = 16; + + private const int Op1ElementCount = VectorSize / sizeof(SByte); + private const int Op2ElementCount = VectorSize / sizeof(SByte); + private const int RetElementCount = VectorSize / sizeof(SByte); + + private static SByte[] _data1 = new SByte[Op1ElementCount]; + private static SByte[] _data2 = new SByte[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private SimpleBinaryOpTest__DataTable _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, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), VectorSize); + } + + 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, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), VectorSize); + + 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(_data1, _data2, new SByte[RetElementCount], VectorSize); + } + + public bool IsSupported => Sse41.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse41.Min( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse41.Min( + Sse2.LoadVector128((SByte*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((SByte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse41.Min( + Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.Min), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.Min), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((SByte*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((SByte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.Min), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse41.Min( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read>(_dataTable.inArray1Ptr); + var right = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = Sse41.Min(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((SByte*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((SByte*)(_dataTable.inArray2Ptr)); + var result = Sse41.Min(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArray2Ptr)); + var result = Sse41.Min(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__MinSByte(); + var result = Sse41.Min(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse41.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(Vector128 left, Vector128 right, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); + + 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(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); + + 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(Sse41)}.{nameof(Sse41.Min)}(Vector128, Vector128): {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/Sse41/Min.UInt16.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/Min.UInt16.cs new file mode 100644 index 000000000000..04ae1dee62c0 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/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 (Sse2.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 (Sse2.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 (Sse2.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 const int VectorSize = 16; + + private const int Op1ElementCount = VectorSize / sizeof(UInt16); + private const int Op2ElementCount = VectorSize / sizeof(UInt16); + private const int RetElementCount = VectorSize / sizeof(UInt16); + + private static UInt16[] _data1 = new UInt16[Op1ElementCount]; + private static UInt16[] _data2 = new UInt16[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private SimpleBinaryOpTest__DataTable _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, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (ushort)(random.Next(0, ushort.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), VectorSize); + } + + 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, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (ushort)(random.Next(0, ushort.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), VectorSize); + + 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(_data1, _data2, new UInt16[RetElementCount], VectorSize); + } + + public bool IsSupported => Sse41.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse41.Min( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse41.Min( + Sse2.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse41.Min( + Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.Min), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.Min), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.Min), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse41.Min( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read>(_dataTable.inArray1Ptr); + var right = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = Sse41.Min(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)); + var result = Sse41.Min(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArray2Ptr)); + var result = Sse41.Min(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__MinUInt16(); + var result = Sse41.Min(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse41.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(Vector128 left, Vector128 right, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); + + 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(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); + + 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(Sse41)}.{nameof(Sse41.Min)}(Vector128, Vector128): {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/Sse41/Min.UInt32.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/Min.UInt32.cs new file mode 100644 index 000000000000..7f05a491521e --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/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 (Sse2.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 (Sse2.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 (Sse2.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 const int VectorSize = 16; + + 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 Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private SimpleBinaryOpTest__DataTable _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, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (uint)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), VectorSize); + } + + 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, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (uint)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(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(_data1, _data2, new UInt32[RetElementCount], VectorSize); + } + + public bool IsSupported => Sse41.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse41.Min( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse41.Min( + Sse2.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse41.Min( + Sse2.LoadAlignedVector128((UInt32*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((UInt32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.Min), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.Min), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.Min), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((UInt32*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((UInt32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse41.Min( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read>(_dataTable.inArray1Ptr); + var right = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = Sse41.Min(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)); + var result = Sse41.Min(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((UInt32*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((UInt32*)(_dataTable.inArray2Ptr)); + var result = Sse41.Min(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__MinUInt32(); + var result = Sse41.Min(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse41.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(Vector128 left, Vector128 right, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(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(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); + + 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(Sse41)}.{nameof(Sse41.Min)}(Vector128, Vector128): {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/Sse41/MinHorizontal.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/MinHorizontal.cs new file mode 100644 index 000000000000..904624b38741 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/MinHorizontal.cs @@ -0,0 +1,318 @@ +// 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.Collections.Generic; +using System.Linq; +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 + { + static Program() + { + TestList = new Dictionary() { + ["MinHorizontal"] = MinHorizontal + }; + } + + private static void MinHorizontal() + { + var test = new SimpleUnaryOpTest__MinHorizontal(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Sse2.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 (Sse2.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 (Sse2.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__MinHorizontal + { + private const int VectorSize = 16; + + private const int Op1ElementCount = VectorSize / sizeof(UInt16); + private const int RetElementCount = VectorSize / sizeof(UInt16); + + private static UInt16[] _data = new UInt16[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private SimpleUnaryOpTest__DataTable _dataTable; + + static SimpleUnaryOpTest__MinHorizontal() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (ushort)(random.Next(0, ushort.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), VectorSize); + } + + public SimpleUnaryOpTest__MinHorizontal() + { + 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, byte>(ref _fld), ref Unsafe.As(ref _data[0]), VectorSize); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (ushort)(random.Next(0, ushort.MaxValue)); } + _dataTable = new SimpleUnaryOpTest__DataTable(_data, new UInt16[RetElementCount], VectorSize); + } + + public bool IsSupported => Sse41.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse41.MinHorizontal( + Unsafe.Read>(_dataTable.inArrayPtr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse41.MinHorizontal( + Sse2.LoadVector128((UInt16*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse41.MinHorizontal( + Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.MinHorizontal), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.MinHorizontal), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((UInt16*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.MinHorizontal), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse41.MinHorizontal( + _clsVar + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = Sse41.MinHorizontal(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var firstOp = Sse2.LoadVector128((UInt16*)(_dataTable.inArrayPtr)); + var result = Sse41.MinHorizontal(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var firstOp = Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArrayPtr)); + var result = Sse41.MinHorizontal(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleUnaryOpTest__MinHorizontal(); + var result = Sse41.MinHorizontal(test._fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse41.MinHorizontal(_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 firstOp, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray = new UInt16[Op1ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray = new UInt16[Op1ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(UInt16[] firstOp, UInt16[] result, [CallerMemberName] string method = "") + { + var minValue = firstOp.Min(); + var minIndex = firstOp.ToList().IndexOf(minValue); + + if ((result[0] != minValue) || (result[1] != minIndex)) + { + Succeeded = false; + } + else + { + for (var i = 2; i < RetElementCount; i++) + { + if (result[i] != 0) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Sse41)}.{nameof(Sse41.MinHorizontal)}(Vector128): {method} failed:"); + Console.WriteLine($" firstOp: ({string.Join(", ", firstOp)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse41/MinHorizontal_r.csproj b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/MinHorizontal_r.csproj new file mode 100644 index 000000000000..fbf52f02ec54 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/MinHorizontal_r.csproj @@ -0,0 +1,36 @@ + + + + + Debug + AnyCPU + 2.0 + {95DFC527-4DC1-495E-97D7-E94EE1F7140D} + Exe + {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + ..\..\ + true + + + + + + + False + + + + None + + + + + + + + + + + + + diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse41/MinHorizontal_ro.csproj b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/MinHorizontal_ro.csproj new file mode 100644 index 000000000000..7cb9febea49e --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/MinHorizontal_ro.csproj @@ -0,0 +1,36 @@ + + + + + Debug + AnyCPU + 2.0 + {95DFC527-4DC1-495E-97D7-E94EE1F7140D} + Exe + {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + ..\..\ + true + + + + + + + False + + + + None + True + + + + + + + + + + + + diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse41/MultipleSumAbsoluteDifferences.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/MultipleSumAbsoluteDifferences.cs new file mode 100644 index 000000000000..9e33e9225846 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/MultipleSumAbsoluteDifferences.cs @@ -0,0 +1,415 @@ +// 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.Collections.Generic; +using System.Linq; +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 + { + static Program() + { + TestList = new Dictionary() { + ["MultipleSumAbsoluteDifferences"] = MultipleSumAbsoluteDifferences + }; + } + + private static void MultipleSumAbsoluteDifferences() + { + var test = new SimpleBinaryOpTest__MultipleSumAbsoluteDifferences(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Sse2.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 (Sse2.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 (Sse2.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__MultipleSumAbsoluteDifferences + { + private const int VectorSize = 16; + + private const int Op1ElementCount = VectorSize / sizeof(Byte); + private const int Op2ElementCount = VectorSize / sizeof(Byte); + private const int RetElementCount = VectorSize / sizeof(UInt16); + + private static Byte[] _data1 = new Byte[Op1ElementCount]; + private static Byte[] _data2 = new Byte[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private SimpleBinaryOpTest__DataTable _dataTable; + + static SimpleBinaryOpTest__MultipleSumAbsoluteDifferences() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (byte)(random.Next(0, byte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (byte)(random.Next(0, byte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), VectorSize); + } + + public SimpleBinaryOpTest__MultipleSumAbsoluteDifferences() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (byte)(random.Next(0, byte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (byte)(random.Next(0, byte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), VectorSize); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (byte)(random.Next(0, byte.MaxValue)); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (byte)(random.Next(0, byte.MaxValue)); } + _dataTable = new SimpleBinaryOpTest__DataTable(_data1, _data2, new UInt16[RetElementCount], VectorSize); + } + + public bool IsSupported => Sse41.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + const byte imm8 = 0; + + var result = Sse41.MultipleSumAbsoluteDifferences( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + imm8 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, imm8, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + const byte imm8 = 1; + + var result = Sse41.MultipleSumAbsoluteDifferences( + Sse2.LoadVector128((Byte*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Byte*)(_dataTable.inArray2Ptr)), + imm8 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, imm8, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + const byte imm8 = 2; + + var result = Sse41.MultipleSumAbsoluteDifferences( + Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray2Ptr)), + imm8 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, imm8, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + const byte imm8 = 3; + + var result = typeof(Sse41).GetMethod(nameof(Sse41.MultipleSumAbsoluteDifferences), new Type[] { typeof(Vector128), typeof(Vector128), typeof(Byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + imm8 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, imm8, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + const byte imm8 = 4; + + var result = typeof(Sse41).GetMethod(nameof(Sse41.MultipleSumAbsoluteDifferences), new Type[] { typeof(Vector128), typeof(Vector128), typeof(Byte) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Byte*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Byte*)(_dataTable.inArray2Ptr)), + imm8 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, imm8, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + const byte imm8 = 5; + + var result = typeof(Sse41).GetMethod(nameof(Sse41.MultipleSumAbsoluteDifferences), new Type[] { typeof(Vector128), typeof(Vector128), typeof(Byte) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray2Ptr)), + imm8 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, imm8, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + const byte imm8 = 6; + + var result = Sse41.MultipleSumAbsoluteDifferences( + _clsVar1, + _clsVar2, + imm8 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, imm8, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + const byte imm8 = 7; + + var left = Unsafe.Read>(_dataTable.inArray1Ptr); + var right = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = Sse41.MultipleSumAbsoluteDifferences(left, right, imm8); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, imm8, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + const byte imm8 = 8; + + var left = Sse2.LoadVector128((Byte*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((Byte*)(_dataTable.inArray2Ptr)); + var result = Sse41.MultipleSumAbsoluteDifferences(left, right, imm8); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, imm8, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + const byte imm8 = 9; + + var left = Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray2Ptr)); + var result = Sse41.MultipleSumAbsoluteDifferences(left, right, imm8); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, imm8, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + const byte imm8 = 10; + + var test = new SimpleBinaryOpTest__MultipleSumAbsoluteDifferences(); + var result = Sse41.MultipleSumAbsoluteDifferences(test._fld1, test._fld2, imm8); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, imm8, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + const byte imm8 = 11; + + var result = Sse41.MultipleSumAbsoluteDifferences(_fld1, _fld2, imm8); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, imm8, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128 left, Vector128 right, byte imm8, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + Byte[] inArray2 = new Byte[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); + + ValidateResult(inArray1, inArray2, imm8, outArray, method); + } + + private void ValidateResult(void* left, void* right, byte imm8, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + Byte[] inArray2 = new Byte[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); + + ValidateResult(inArray1, inArray2, imm8, outArray, method); + } + + private void ValidateResult(Byte[] left, Byte[] right, byte imm8, UInt16[] result, [CallerMemberName] string method = "") + { + var srcOffset = ((imm8 & 0x3) * 32) / 8; + var dstOffset = (((imm8 & 0x4) >> 2) * 32) / 8; + + if (result[0] != Math.Abs(left[dstOffset + 0] - right[srcOffset + 0]) + + Math.Abs(left[dstOffset + 1] - right[srcOffset + 1]) + + Math.Abs(left[dstOffset + 2] - right[srcOffset + 2]) + + Math.Abs(left[dstOffset + 3] - right[srcOffset + 3])) + { + Succeeded = false; + } + else if (result[1] != Math.Abs(left[dstOffset + 1] - right[srcOffset + 0]) + + Math.Abs(left[dstOffset + 2] - right[srcOffset + 1]) + + Math.Abs(left[dstOffset + 3] - right[srcOffset + 2]) + + Math.Abs(left[dstOffset + 4] - right[srcOffset + 3])) + { + Succeeded = false; + } + else if (result[2] != Math.Abs(left[dstOffset + 2] - right[srcOffset + 0]) + + Math.Abs(left[dstOffset + 3] - right[srcOffset + 1]) + + Math.Abs(left[dstOffset + 4] - right[srcOffset + 2]) + + Math.Abs(left[dstOffset + 5] - right[srcOffset + 3])) + { + Succeeded = false; + } + else if (result[3] != Math.Abs(left[dstOffset + 3] - right[srcOffset + 0]) + + Math.Abs(left[dstOffset + 4] - right[srcOffset + 1]) + + Math.Abs(left[dstOffset + 5] - right[srcOffset + 2]) + + Math.Abs(left[dstOffset + 6] - right[srcOffset + 3])) + { + Succeeded = false; + } + else if (result[4] != Math.Abs(left[dstOffset + 4] - right[srcOffset + 0]) + + Math.Abs(left[dstOffset + 5] - right[srcOffset + 1]) + + Math.Abs(left[dstOffset + 6] - right[srcOffset + 2]) + + Math.Abs(left[dstOffset + 7] - right[srcOffset + 3])) + { + Succeeded = false; + } + else if (result[5] != Math.Abs(left[dstOffset + 5] - right[srcOffset + 0]) + + Math.Abs(left[dstOffset + 6] - right[srcOffset + 1]) + + Math.Abs(left[dstOffset + 7] - right[srcOffset + 2]) + + Math.Abs(left[dstOffset + 8] - right[srcOffset + 3])) + { + Succeeded = false; + } + else if (result[6] != Math.Abs(left[dstOffset + 6] - right[srcOffset + 0]) + + Math.Abs(left[dstOffset + 7] - right[srcOffset + 1]) + + Math.Abs(left[dstOffset + 8] - right[srcOffset + 2]) + + Math.Abs(left[dstOffset + 9] - right[srcOffset + 3])) + { + Succeeded = false; + } + else if (result[7] != Math.Abs(left[dstOffset + 7] - right[srcOffset + 0]) + + Math.Abs(left[dstOffset + 8] - right[srcOffset + 1]) + + Math.Abs(left[dstOffset + 9] - right[srcOffset + 2]) + + Math.Abs(left[dstOffset + 10] - right[srcOffset + 3])) + { + Succeeded = false; + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Sse41)}.{nameof(Sse41.MultipleSumAbsoluteDifferences)}Vector128(Vector128, Vector128, Byte): {method} failed:"); + Console.WriteLine($" left: ({string.Join(", ", left)})"); + Console.WriteLine($" right: ({string.Join(", ", right)})"); + Console.WriteLine($" imm8: ({imm8})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse41/MultipleSumAbsoluteDifferences_r.csproj b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/MultipleSumAbsoluteDifferences_r.csproj new file mode 100644 index 000000000000..cca08717eca9 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/MultipleSumAbsoluteDifferences_r.csproj @@ -0,0 +1,36 @@ + + + + + Debug + AnyCPU + 2.0 + {95DFC527-4DC1-495E-97D7-E94EE1F7140D} + Exe + {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + ..\..\ + true + + + + + + + False + + + + None + + + + + + + + + + + + + diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse41/MultipleSumAbsoluteDifferences_ro.csproj b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/MultipleSumAbsoluteDifferences_ro.csproj new file mode 100644 index 000000000000..16ba328a2640 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/MultipleSumAbsoluteDifferences_ro.csproj @@ -0,0 +1,36 @@ + + + + + Debug + AnyCPU + 2.0 + {95DFC527-4DC1-495E-97D7-E94EE1F7140D} + Exe + {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + ..\..\ + true + + + + + + + False + + + + None + True + + + + + + + + + + + + diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse41/MultiplyLow.Int32.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/MultiplyLow.Int32.cs new file mode 100644 index 000000000000..2178a2c20484 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/MultiplyLow.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 MultiplyLowInt32() + { + var test = new SimpleBinaryOpTest__MultiplyLowInt32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Sse2.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 (Sse2.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 (Sse2.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__MultiplyLowInt32 + { + private const int VectorSize = 16; + + 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 Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private SimpleBinaryOpTest__DataTable _dataTable; + + static SimpleBinaryOpTest__MultiplyLowInt32() + { + 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, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (int)(random.Next(int.MinValue, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), VectorSize); + } + + public SimpleBinaryOpTest__MultiplyLowInt32() + { + 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, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (int)(random.Next(int.MinValue, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), VectorSize); + + 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(_data1, _data2, new Int32[RetElementCount], VectorSize); + } + + public bool IsSupported => Sse41.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse41.MultiplyLow( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse41.MultiplyLow( + Sse2.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Int32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse41.MultiplyLow( + Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.MultiplyLow), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.MultiplyLow), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Int32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.MultiplyLow), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse41.MultiplyLow( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read>(_dataTable.inArray1Ptr); + var right = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = Sse41.MultiplyLow(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((Int32*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((Int32*)(_dataTable.inArray2Ptr)); + var result = Sse41.MultiplyLow(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray2Ptr)); + var result = Sse41.MultiplyLow(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__MultiplyLowInt32(); + var result = Sse41.MultiplyLow(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse41.MultiplyLow(_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(Vector128 left, Vector128 right, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(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(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int32[] left, Int32[] right, Int32[] result, [CallerMemberName] string method = "") + { + if (result[0] != BitConverter.ToInt32(BitConverter.GetBytes(((long)(left[0])) * right[0]), 0)) + { + Succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != BitConverter.ToInt32(BitConverter.GetBytes(((long)(left[i])) * right[i]), 0)) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Sse41)}.{nameof(Sse41.MultiplyLow)}(Vector128, Vector128): {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/Sse41/PackUnsignedSaturate.UInt16.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/PackUnsignedSaturate.UInt16.cs new file mode 100644 index 000000000000..47db6aee22e4 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/PackUnsignedSaturate.UInt16.cs @@ -0,0 +1,336 @@ +// 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 PackUnsignedSaturateUInt16() + { + var test = new HorizontalBinaryOpTest__PackUnsignedSaturateUInt16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Sse2.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 (Sse2.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 (Sse2.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 HorizontalBinaryOpTest__PackUnsignedSaturateUInt16 + { + private const int VectorSize = 16; + + private const int Op1ElementCount = VectorSize / sizeof(Int32); + private const int Op2ElementCount = VectorSize / sizeof(Int32); + private const int RetElementCount = VectorSize / sizeof(UInt16); + + private static Int32[] _data1 = new Int32[Op1ElementCount]; + private static Int32[] _data2 = new Int32[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private HorizontalBinaryOpTest__DataTable _dataTable; + + static HorizontalBinaryOpTest__PackUnsignedSaturateUInt16() + { + 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, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (int)(random.Next(int.MinValue, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), VectorSize); + } + + public HorizontalBinaryOpTest__PackUnsignedSaturateUInt16() + { + 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, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (int)(random.Next(int.MinValue, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), VectorSize); + + 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 HorizontalBinaryOpTest__DataTable(_data1, _data2, new UInt16[RetElementCount], VectorSize); + } + + public bool IsSupported => Sse41.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse41.PackUnsignedSaturate( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse41.PackUnsignedSaturate( + Sse2.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Int32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse41.PackUnsignedSaturate( + Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.PackUnsignedSaturate), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.PackUnsignedSaturate), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Int32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.PackUnsignedSaturate), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse41.PackUnsignedSaturate( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read>(_dataTable.inArray1Ptr); + var right = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = Sse41.PackUnsignedSaturate(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((Int32*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((Int32*)(_dataTable.inArray2Ptr)); + var result = Sse41.PackUnsignedSaturate(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray2Ptr)); + var result = Sse41.PackUnsignedSaturate(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new HorizontalBinaryOpTest__PackUnsignedSaturateUInt16(); + var result = Sse41.PackUnsignedSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse41.PackUnsignedSaturate(_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(Vector128 left, Vector128 right, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(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]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int32[] left, Int32[] right, UInt16[] result, [CallerMemberName] string method = "") + { + for (var outer = 0; outer < (VectorSize / 16); outer++) + { + for (var inner = 0; inner < (8 / sizeof(UInt16)); inner++) + { + var i1 = (outer * (16 / sizeof(UInt16))) + inner; + var i2 = i1 + (8 / sizeof(UInt16)); + var i3 = (outer * (16 / sizeof(UInt16))) + (inner * 2); + + if (result[i1] != ((left[i3 - inner] > 0xFFFF) ? 0xFFFF : ((left[i3 - inner] < 0) ? 0 : BitConverter.ToUInt16(BitConverter.GetBytes(left[i3 - inner]), 0)))) + { + Succeeded = false; + break; + } + + if (result[i2] != ((right[i3 - inner] > 0xFFFF) ? 0xFFFF : ((right[i3 - inner] < 0) ? 0 : BitConverter.ToUInt16(BitConverter.GetBytes(right[i3 - inner]), 0)))) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Sse41)}.{nameof(Sse41.PackUnsignedSaturate)}(Vector128, Vector128): {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/Sse41/Program.ConvertToVector128.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/Program.ConvertToVector128.cs new file mode 100644 index 000000000000..d7f3e102d6c1 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/Program.ConvertToVector128.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() { + ["ConvertToVector128Int16.Byte"] = ConvertToVector128Int16Byte, + ["ConvertToVector128Int16.SByte"] = ConvertToVector128Int16SByte, + ["ConvertToVector128Int32.Byte"] = ConvertToVector128Int32Byte, + ["ConvertToVector128Int32.Int16"] = ConvertToVector128Int32Int16, + ["ConvertToVector128Int32.SByte"] = ConvertToVector128Int32SByte, + ["ConvertToVector128Int32.UInt16"] = ConvertToVector128Int32UInt16, + ["ConvertToVector128Int64.Byte"] = ConvertToVector128Int64Byte, + ["ConvertToVector128Int64.Int16"] = ConvertToVector128Int64Int16, + ["ConvertToVector128Int64.Int32"] = ConvertToVector128Int64Int32, + ["ConvertToVector128Int64.SByte"] = ConvertToVector128Int64SByte, + ["ConvertToVector128Int64.UInt16"] = ConvertToVector128Int64UInt16, + ["ConvertToVector128Int64.UInt32"] = ConvertToVector128Int64UInt32, + }; + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse41/Program.Sse41.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/Program.Sse41.cs index a71a4b13dea0..c941543373bb 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse41/Program.Sse41.cs +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/Program.Sse41.cs @@ -12,8 +12,98 @@ public static partial class Program static Program() { TestList = new Dictionary() { + ["BlendVariable.Byte"] = BlendVariableByte, + ["BlendVariable.Double"] = BlendVariableDouble, + ["BlendVariable.SByte"] = BlendVariableSByte, + ["BlendVariable.Single"] = BlendVariableSingle, + ["Ceiling.Double"] = CeilingDouble, + ["Ceiling.Single"] = CeilingSingle, + ["CeilingScalar.Double"] = CeilingScalarDouble, + ["CeilingScalar.Single"] = CeilingScalarSingle, ["CompareEqual.Int64"] = CompareEqualInt64, ["CompareEqual.UInt64"] = CompareEqualUInt64, + ["Floor.Double"] = FloorDouble, + ["Floor.Single"] = FloorSingle, + ["FloorScalar.Double"] = FloorScalarDouble, + ["FloorScalar.Single"] = FloorScalarSingle, + ["Max.Int32"] = MaxInt32, + ["Max.SByte"] = MaxSByte, + ["Max.UInt16"] = MaxUInt16, + ["Max.UInt32"] = MaxUInt32, + ["Min.Int32"] = MinInt32, + ["Min.SByte"] = MinSByte, + ["Min.UInt16"] = MinUInt16, + ["Min.UInt32"] = MinUInt32, + ["MultiplyLow.Int32"] = MultiplyLowInt32, + ["PackUnsignedSaturate.UInt16"] = PackUnsignedSaturateUInt16, + ["RoundCurrentDirection.Double"] = RoundCurrentDirectionDouble, + ["RoundCurrentDirection.Single"] = RoundCurrentDirectionSingle, + ["RoundCurrentDirectionScalar.Double"] = RoundCurrentDirectionScalarDouble, + ["RoundCurrentDirectionScalar.Single"] = RoundCurrentDirectionScalarSingle, + ["RoundToNearestInteger.Double"] = RoundToNearestIntegerDouble, + ["RoundToNearestInteger.Single"] = RoundToNearestIntegerSingle, + ["RoundToNearestIntegerScalar.Double"] = RoundToNearestIntegerScalarDouble, + ["RoundToNearestIntegerScalar.Single"] = RoundToNearestIntegerScalarSingle, + ["RoundToNegativeInfinity.Double"] = RoundToNegativeInfinityDouble, + ["RoundToNegativeInfinity.Single"] = RoundToNegativeInfinitySingle, + ["RoundToNegativeInfinityScalar.Double"] = RoundToNegativeInfinityScalarDouble, + ["RoundToNegativeInfinityScalar.Single"] = RoundToNegativeInfinityScalarSingle, + ["RoundToPositiveInfinity.Double"] = RoundToPositiveInfinityDouble, + ["RoundToPositiveInfinity.Single"] = RoundToPositiveInfinitySingle, + ["RoundToPositiveInfinityScalar.Double"] = RoundToPositiveInfinityScalarDouble, + ["RoundToPositiveInfinityScalar.Single"] = RoundToPositiveInfinityScalarSingle, + ["RoundToZero.Double"] = RoundToZeroDouble, + ["RoundToZero.Single"] = RoundToZeroSingle, + ["RoundToZeroScalar.Double"] = RoundToZeroScalarDouble, + ["RoundToZeroScalar.Single"] = RoundToZeroScalarSingle, + ["TestAllOnes.Byte"] = TestAllOnesByte, + ["TestAllOnes.Int16"] = TestAllOnesInt16, + ["TestAllOnes.Int32"] = TestAllOnesInt32, + ["TestAllOnes.Int64"] = TestAllOnesInt64, + ["TestAllOnes.SByte"] = TestAllOnesSByte, + ["TestAllOnes.UInt16"] = TestAllOnesUInt16, + ["TestAllOnes.UInt32"] = TestAllOnesUInt32, + ["TestAllOnes.UInt64"] = TestAllOnesUInt64, + ["TestAllZeros.Byte"] = TestAllZerosByte, + ["TestAllZeros.Int16"] = TestAllZerosInt16, + ["TestAllZeros.Int32"] = TestAllZerosInt32, + ["TestAllZeros.Int64"] = TestAllZerosInt64, + ["TestAllZeros.SByte"] = TestAllZerosSByte, + ["TestAllZeros.UInt16"] = TestAllZerosUInt16, + ["TestAllZeros.UInt32"] = TestAllZerosUInt32, + ["TestAllZeros.UInt64"] = TestAllZerosUInt64, + ["TestC.Byte"] = TestCByte, + ["TestC.Int16"] = TestCInt16, + ["TestC.Int32"] = TestCInt32, + ["TestC.Int64"] = TestCInt64, + ["TestC.SByte"] = TestCSByte, + ["TestC.UInt16"] = TestCUInt16, + ["TestC.UInt32"] = TestCUInt32, + ["TestC.UInt64"] = TestCUInt64, + ["TestMixOnesZeros.Byte"] = TestMixOnesZerosByte, + ["TestMixOnesZeros.Int16"] = TestMixOnesZerosInt16, + ["TestMixOnesZeros.Int32"] = TestMixOnesZerosInt32, + ["TestMixOnesZeros.Int64"] = TestMixOnesZerosInt64, + ["TestMixOnesZeros.SByte"] = TestMixOnesZerosSByte, + ["TestMixOnesZeros.UInt16"] = TestMixOnesZerosUInt16, + ["TestMixOnesZeros.UInt32"] = TestMixOnesZerosUInt32, + ["TestMixOnesZeros.UInt64"] = TestMixOnesZerosUInt64, + ["TestNotZAndNotC.Byte"] = TestNotZAndNotCByte, + ["TestNotZAndNotC.Int16"] = TestNotZAndNotCInt16, + ["TestNotZAndNotC.Int32"] = TestNotZAndNotCInt32, + ["TestNotZAndNotC.Int64"] = TestNotZAndNotCInt64, + ["TestNotZAndNotC.SByte"] = TestNotZAndNotCSByte, + ["TestNotZAndNotC.UInt16"] = TestNotZAndNotCUInt16, + ["TestNotZAndNotC.UInt32"] = TestNotZAndNotCUInt32, + ["TestNotZAndNotC.UInt64"] = TestNotZAndNotCUInt64, + ["TestZ.Byte"] = TestZByte, + ["TestZ.Int16"] = TestZInt16, + ["TestZ.Int32"] = TestZInt32, + ["TestZ.Int64"] = TestZInt64, + ["TestZ.SByte"] = TestZSByte, + ["TestZ.UInt16"] = TestZUInt16, + ["TestZ.UInt32"] = TestZUInt32, + ["TestZ.UInt64"] = TestZUInt64, }; } } diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse41/RoundCurrentDirection.Double.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/RoundCurrentDirection.Double.cs new file mode 100644 index 000000000000..b8c25f73d7cd --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/RoundCurrentDirection.Double.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 RoundCurrentDirectionDouble() + { + var test = new SimpleUnaryOpTest__RoundCurrentDirectionDouble(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Sse2.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 (Sse2.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 (Sse2.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__RoundCurrentDirectionDouble + { + private const int VectorSize = 16; + + private const int Op1ElementCount = VectorSize / sizeof(Double); + private const int RetElementCount = VectorSize / sizeof(Double); + + private static Double[] _data = new Double[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private SimpleUnaryOpTest__DataTable _dataTable; + + static SimpleUnaryOpTest__RoundCurrentDirectionDouble() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (double)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), VectorSize); + } + + public SimpleUnaryOpTest__RoundCurrentDirectionDouble() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (double)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), VectorSize); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (double)(random.NextDouble()); } + _dataTable = new SimpleUnaryOpTest__DataTable(_data, new Double[RetElementCount], VectorSize); + } + + public bool IsSupported => Sse41.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse41.RoundCurrentDirection( + Unsafe.Read>(_dataTable.inArrayPtr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse41.RoundCurrentDirection( + Sse2.LoadVector128((Double*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse41.RoundCurrentDirection( + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.RoundCurrentDirection), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.RoundCurrentDirection), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Double*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.RoundCurrentDirection), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse41.RoundCurrentDirection( + _clsVar + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = Sse41.RoundCurrentDirection(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var firstOp = Sse2.LoadVector128((Double*)(_dataTable.inArrayPtr)); + var result = Sse41.RoundCurrentDirection(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var firstOp = Sse2.LoadAlignedVector128((Double*)(_dataTable.inArrayPtr)); + var result = Sse41.RoundCurrentDirection(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleUnaryOpTest__RoundCurrentDirectionDouble(); + var result = Sse41.RoundCurrentDirection(test._fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse41.RoundCurrentDirection(_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 firstOp, void* result, [CallerMemberName] string method = "") + { + Double[] inArray = new Double[Op1ElementCount]; + Double[] outArray = new Double[RetElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Double[] inArray = new Double[Op1ElementCount]; + Double[] outArray = new Double[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Double[] firstOp, Double[] result, [CallerMemberName] string method = "") + { + if (BitConverter.DoubleToInt64Bits(result[0]) != BitConverter.DoubleToInt64Bits(Math.Round(firstOp[0]))) + { + Succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (BitConverter.DoubleToInt64Bits(result[i]) != BitConverter.DoubleToInt64Bits(Math.Round(firstOp[i]))) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Sse41)}.{nameof(Sse41.RoundCurrentDirection)}(Vector128): {method} failed:"); + Console.WriteLine($" firstOp: ({string.Join(", ", firstOp)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse41/RoundCurrentDirection.Single.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/RoundCurrentDirection.Single.cs new file mode 100644 index 000000000000..137859853cb2 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/RoundCurrentDirection.Single.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 RoundCurrentDirectionSingle() + { + var test = new SimpleUnaryOpTest__RoundCurrentDirectionSingle(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Sse.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 (Sse.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 (Sse.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__RoundCurrentDirectionSingle + { + private const int VectorSize = 16; + + private const int Op1ElementCount = VectorSize / sizeof(Single); + private const int RetElementCount = VectorSize / sizeof(Single); + + private static Single[] _data = new Single[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private SimpleUnaryOpTest__DataTable _dataTable; + + static SimpleUnaryOpTest__RoundCurrentDirectionSingle() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (float)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), VectorSize); + } + + public SimpleUnaryOpTest__RoundCurrentDirectionSingle() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (float)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), VectorSize); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (float)(random.NextDouble()); } + _dataTable = new SimpleUnaryOpTest__DataTable(_data, new Single[RetElementCount], VectorSize); + } + + public bool IsSupported => Sse41.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse41.RoundCurrentDirection( + Unsafe.Read>(_dataTable.inArrayPtr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse41.RoundCurrentDirection( + Sse.LoadVector128((Single*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse41.RoundCurrentDirection( + Sse.LoadAlignedVector128((Single*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.RoundCurrentDirection), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.RoundCurrentDirection), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadVector128((Single*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.RoundCurrentDirection), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadAlignedVector128((Single*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse41.RoundCurrentDirection( + _clsVar + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = Sse41.RoundCurrentDirection(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var firstOp = Sse.LoadVector128((Single*)(_dataTable.inArrayPtr)); + var result = Sse41.RoundCurrentDirection(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var firstOp = Sse.LoadAlignedVector128((Single*)(_dataTable.inArrayPtr)); + var result = Sse41.RoundCurrentDirection(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleUnaryOpTest__RoundCurrentDirectionSingle(); + var result = Sse41.RoundCurrentDirection(test._fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse41.RoundCurrentDirection(_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 firstOp, void* result, [CallerMemberName] string method = "") + { + Single[] inArray = new Single[Op1ElementCount]; + Single[] outArray = new Single[RetElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Single[] inArray = new Single[Op1ElementCount]; + Single[] outArray = new Single[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Single[] firstOp, Single[] result, [CallerMemberName] string method = "") + { + if (BitConverter.SingleToInt32Bits(result[0]) != BitConverter.SingleToInt32Bits(MathF.Round(firstOp[0]))) + { + Succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (BitConverter.SingleToInt32Bits(result[i]) != BitConverter.SingleToInt32Bits(MathF.Round(firstOp[i]))) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Sse41)}.{nameof(Sse41.RoundCurrentDirection)}(Vector128): {method} failed:"); + Console.WriteLine($" firstOp: ({string.Join(", ", firstOp)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse41/RoundCurrentDirectionScalar.Double.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/RoundCurrentDirectionScalar.Double.cs new file mode 100644 index 000000000000..b0bc41778cde --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/RoundCurrentDirectionScalar.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 RoundCurrentDirectionScalarDouble() + { + var test = new SimpleBinaryOpTest__RoundCurrentDirectionScalarDouble(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Sse2.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 (Sse2.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 (Sse2.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__RoundCurrentDirectionScalarDouble + { + private const int VectorSize = 16; + + 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 Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private SimpleBinaryOpTest__DataTable _dataTable; + + static SimpleBinaryOpTest__RoundCurrentDirectionScalarDouble() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (double)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (double)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), VectorSize); + } + + public SimpleBinaryOpTest__RoundCurrentDirectionScalarDouble() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (double)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (double)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(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(_data1, _data2, new Double[RetElementCount], VectorSize); + } + + public bool IsSupported => Sse41.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse41.RoundCurrentDirectionScalar( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse41.RoundCurrentDirectionScalar( + Sse2.LoadVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Double*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse41.RoundCurrentDirectionScalar( + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.RoundCurrentDirectionScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.RoundCurrentDirectionScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Double*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.RoundCurrentDirectionScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse41.RoundCurrentDirectionScalar( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read>(_dataTable.inArray1Ptr); + var right = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = Sse41.RoundCurrentDirectionScalar(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((Double*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((Double*)(_dataTable.inArray2Ptr)); + var result = Sse41.RoundCurrentDirectionScalar(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray2Ptr)); + var result = Sse41.RoundCurrentDirectionScalar(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__RoundCurrentDirectionScalarDouble(); + var result = Sse41.RoundCurrentDirectionScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse41.RoundCurrentDirectionScalar(_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(Vector128 left, Vector128 right, void* result, [CallerMemberName] string method = "") + { + Double[] inArray1 = new Double[Op1ElementCount]; + Double[] inArray2 = new Double[Op2ElementCount]; + Double[] outArray = new Double[RetElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(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(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(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(Math.Round(right[0]))) + { + Succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (BitConverter.DoubleToInt64Bits(result[i]) != BitConverter.DoubleToInt64Bits(left[i])) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Sse41)}.{nameof(Sse41.RoundCurrentDirectionScalar)}(Vector128, Vector128): {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/Sse41/RoundCurrentDirectionScalar.Single.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/RoundCurrentDirectionScalar.Single.cs new file mode 100644 index 000000000000..3639a34c11dd --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/RoundCurrentDirectionScalar.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 RoundCurrentDirectionScalarSingle() + { + var test = new SimpleBinaryOpTest__RoundCurrentDirectionScalarSingle(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Sse.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 (Sse.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 (Sse.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__RoundCurrentDirectionScalarSingle + { + private const int VectorSize = 16; + + 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 Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private SimpleBinaryOpTest__DataTable _dataTable; + + static SimpleBinaryOpTest__RoundCurrentDirectionScalarSingle() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (float)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (float)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), VectorSize); + } + + public SimpleBinaryOpTest__RoundCurrentDirectionScalarSingle() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (float)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (float)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(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(_data1, _data2, new Single[RetElementCount], VectorSize); + } + + public bool IsSupported => Sse41.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse41.RoundCurrentDirectionScalar( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse41.RoundCurrentDirectionScalar( + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse41.RoundCurrentDirectionScalar( + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.RoundCurrentDirectionScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.RoundCurrentDirectionScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.RoundCurrentDirectionScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse41.RoundCurrentDirectionScalar( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read>(_dataTable.inArray1Ptr); + var right = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = Sse41.RoundCurrentDirectionScalar(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse41.RoundCurrentDirectionScalar(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse41.RoundCurrentDirectionScalar(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__RoundCurrentDirectionScalarSingle(); + var result = Sse41.RoundCurrentDirectionScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse41.RoundCurrentDirectionScalar(_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(Vector128 left, Vector128 right, void* result, [CallerMemberName] string method = "") + { + Single[] inArray1 = new Single[Op1ElementCount]; + Single[] inArray2 = new Single[Op2ElementCount]; + Single[] outArray = new Single[RetElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(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(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(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(MathF.Round(right[0]))) + { + Succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (BitConverter.SingleToInt32Bits(result[i]) != BitConverter.SingleToInt32Bits(left[i])) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Sse41)}.{nameof(Sse41.RoundCurrentDirectionScalar)}(Vector128, Vector128): {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/Sse41/RoundToNearestInteger.Double.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/RoundToNearestInteger.Double.cs new file mode 100644 index 000000000000..7b5de3c39e45 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/RoundToNearestInteger.Double.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 RoundToNearestIntegerDouble() + { + var test = new SimpleUnaryOpTest__RoundToNearestIntegerDouble(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Sse2.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 (Sse2.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 (Sse2.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__RoundToNearestIntegerDouble + { + private const int VectorSize = 16; + + private const int Op1ElementCount = VectorSize / sizeof(Double); + private const int RetElementCount = VectorSize / sizeof(Double); + + private static Double[] _data = new Double[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private SimpleUnaryOpTest__DataTable _dataTable; + + static SimpleUnaryOpTest__RoundToNearestIntegerDouble() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (double)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), VectorSize); + } + + public SimpleUnaryOpTest__RoundToNearestIntegerDouble() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (double)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), VectorSize); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (double)(random.NextDouble()); } + _dataTable = new SimpleUnaryOpTest__DataTable(_data, new Double[RetElementCount], VectorSize); + } + + public bool IsSupported => Sse41.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse41.RoundToNearestInteger( + Unsafe.Read>(_dataTable.inArrayPtr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse41.RoundToNearestInteger( + Sse2.LoadVector128((Double*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse41.RoundToNearestInteger( + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.RoundToNearestInteger), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.RoundToNearestInteger), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Double*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.RoundToNearestInteger), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse41.RoundToNearestInteger( + _clsVar + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = Sse41.RoundToNearestInteger(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var firstOp = Sse2.LoadVector128((Double*)(_dataTable.inArrayPtr)); + var result = Sse41.RoundToNearestInteger(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var firstOp = Sse2.LoadAlignedVector128((Double*)(_dataTable.inArrayPtr)); + var result = Sse41.RoundToNearestInteger(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleUnaryOpTest__RoundToNearestIntegerDouble(); + var result = Sse41.RoundToNearestInteger(test._fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse41.RoundToNearestInteger(_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 firstOp, void* result, [CallerMemberName] string method = "") + { + Double[] inArray = new Double[Op1ElementCount]; + Double[] outArray = new Double[RetElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Double[] inArray = new Double[Op1ElementCount]; + Double[] outArray = new Double[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Double[] firstOp, Double[] result, [CallerMemberName] string method = "") + { + if (BitConverter.DoubleToInt64Bits(result[0]) != BitConverter.DoubleToInt64Bits(Math.Round(firstOp[0], MidpointRounding.AwayFromZero))) + { + Succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (BitConverter.DoubleToInt64Bits(result[i]) != BitConverter.DoubleToInt64Bits(Math.Round(firstOp[i], MidpointRounding.AwayFromZero))) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Sse41)}.{nameof(Sse41.RoundToNearestInteger)}(Vector128): {method} failed:"); + Console.WriteLine($" firstOp: ({string.Join(", ", firstOp)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse41/RoundToNearestInteger.Single.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/RoundToNearestInteger.Single.cs new file mode 100644 index 000000000000..a02f1f688b4f --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/RoundToNearestInteger.Single.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 RoundToNearestIntegerSingle() + { + var test = new SimpleUnaryOpTest__RoundToNearestIntegerSingle(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Sse.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 (Sse.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 (Sse.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__RoundToNearestIntegerSingle + { + private const int VectorSize = 16; + + private const int Op1ElementCount = VectorSize / sizeof(Single); + private const int RetElementCount = VectorSize / sizeof(Single); + + private static Single[] _data = new Single[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private SimpleUnaryOpTest__DataTable _dataTable; + + static SimpleUnaryOpTest__RoundToNearestIntegerSingle() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (float)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), VectorSize); + } + + public SimpleUnaryOpTest__RoundToNearestIntegerSingle() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (float)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), VectorSize); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (float)(random.NextDouble()); } + _dataTable = new SimpleUnaryOpTest__DataTable(_data, new Single[RetElementCount], VectorSize); + } + + public bool IsSupported => Sse41.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse41.RoundToNearestInteger( + Unsafe.Read>(_dataTable.inArrayPtr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse41.RoundToNearestInteger( + Sse.LoadVector128((Single*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse41.RoundToNearestInteger( + Sse.LoadAlignedVector128((Single*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.RoundToNearestInteger), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.RoundToNearestInteger), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadVector128((Single*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.RoundToNearestInteger), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadAlignedVector128((Single*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse41.RoundToNearestInteger( + _clsVar + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = Sse41.RoundToNearestInteger(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var firstOp = Sse.LoadVector128((Single*)(_dataTable.inArrayPtr)); + var result = Sse41.RoundToNearestInteger(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var firstOp = Sse.LoadAlignedVector128((Single*)(_dataTable.inArrayPtr)); + var result = Sse41.RoundToNearestInteger(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleUnaryOpTest__RoundToNearestIntegerSingle(); + var result = Sse41.RoundToNearestInteger(test._fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse41.RoundToNearestInteger(_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 firstOp, void* result, [CallerMemberName] string method = "") + { + Single[] inArray = new Single[Op1ElementCount]; + Single[] outArray = new Single[RetElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Single[] inArray = new Single[Op1ElementCount]; + Single[] outArray = new Single[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Single[] firstOp, Single[] result, [CallerMemberName] string method = "") + { + if (BitConverter.SingleToInt32Bits(result[0]) != BitConverter.SingleToInt32Bits(MathF.Round(firstOp[0], MidpointRounding.AwayFromZero))) + { + Succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (BitConverter.SingleToInt32Bits(result[i]) != BitConverter.SingleToInt32Bits(MathF.Round(firstOp[i], MidpointRounding.AwayFromZero))) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Sse41)}.{nameof(Sse41.RoundToNearestInteger)}(Vector128): {method} failed:"); + Console.WriteLine($" firstOp: ({string.Join(", ", firstOp)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse41/RoundToNearestIntegerScalar.Double.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/RoundToNearestIntegerScalar.Double.cs new file mode 100644 index 000000000000..b9c135cd0519 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/RoundToNearestIntegerScalar.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 RoundToNearestIntegerScalarDouble() + { + var test = new SimpleBinaryOpTest__RoundToNearestIntegerScalarDouble(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Sse2.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 (Sse2.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 (Sse2.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__RoundToNearestIntegerScalarDouble + { + private const int VectorSize = 16; + + 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 Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private SimpleBinaryOpTest__DataTable _dataTable; + + static SimpleBinaryOpTest__RoundToNearestIntegerScalarDouble() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (double)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (double)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), VectorSize); + } + + public SimpleBinaryOpTest__RoundToNearestIntegerScalarDouble() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (double)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (double)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(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(_data1, _data2, new Double[RetElementCount], VectorSize); + } + + public bool IsSupported => Sse41.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse41.RoundToNearestIntegerScalar( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse41.RoundToNearestIntegerScalar( + Sse2.LoadVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Double*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse41.RoundToNearestIntegerScalar( + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.RoundToNearestIntegerScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.RoundToNearestIntegerScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Double*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.RoundToNearestIntegerScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse41.RoundToNearestIntegerScalar( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read>(_dataTable.inArray1Ptr); + var right = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = Sse41.RoundToNearestIntegerScalar(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((Double*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((Double*)(_dataTable.inArray2Ptr)); + var result = Sse41.RoundToNearestIntegerScalar(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray2Ptr)); + var result = Sse41.RoundToNearestIntegerScalar(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__RoundToNearestIntegerScalarDouble(); + var result = Sse41.RoundToNearestIntegerScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse41.RoundToNearestIntegerScalar(_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(Vector128 left, Vector128 right, void* result, [CallerMemberName] string method = "") + { + Double[] inArray1 = new Double[Op1ElementCount]; + Double[] inArray2 = new Double[Op2ElementCount]; + Double[] outArray = new Double[RetElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(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(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(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(Math.Round(right[0], MidpointRounding.AwayFromZero))) + { + Succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (BitConverter.DoubleToInt64Bits(result[i]) != BitConverter.DoubleToInt64Bits(left[i])) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Sse41)}.{nameof(Sse41.RoundToNearestIntegerScalar)}(Vector128, Vector128): {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/Sse41/RoundToNearestIntegerScalar.Single.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/RoundToNearestIntegerScalar.Single.cs new file mode 100644 index 000000000000..8d9d228e35e6 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/RoundToNearestIntegerScalar.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 RoundToNearestIntegerScalarSingle() + { + var test = new SimpleBinaryOpTest__RoundToNearestIntegerScalarSingle(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Sse.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 (Sse.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 (Sse.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__RoundToNearestIntegerScalarSingle + { + private const int VectorSize = 16; + + 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 Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private SimpleBinaryOpTest__DataTable _dataTable; + + static SimpleBinaryOpTest__RoundToNearestIntegerScalarSingle() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (float)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (float)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), VectorSize); + } + + public SimpleBinaryOpTest__RoundToNearestIntegerScalarSingle() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (float)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (float)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(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(_data1, _data2, new Single[RetElementCount], VectorSize); + } + + public bool IsSupported => Sse41.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse41.RoundToNearestIntegerScalar( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse41.RoundToNearestIntegerScalar( + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse41.RoundToNearestIntegerScalar( + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.RoundToNearestIntegerScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.RoundToNearestIntegerScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.RoundToNearestIntegerScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse41.RoundToNearestIntegerScalar( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read>(_dataTable.inArray1Ptr); + var right = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = Sse41.RoundToNearestIntegerScalar(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse41.RoundToNearestIntegerScalar(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse41.RoundToNearestIntegerScalar(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__RoundToNearestIntegerScalarSingle(); + var result = Sse41.RoundToNearestIntegerScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse41.RoundToNearestIntegerScalar(_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(Vector128 left, Vector128 right, void* result, [CallerMemberName] string method = "") + { + Single[] inArray1 = new Single[Op1ElementCount]; + Single[] inArray2 = new Single[Op2ElementCount]; + Single[] outArray = new Single[RetElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(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(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(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(MathF.Round(right[0], MidpointRounding.AwayFromZero))) + { + Succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (BitConverter.SingleToInt32Bits(result[i]) != BitConverter.SingleToInt32Bits(left[i])) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Sse41)}.{nameof(Sse41.RoundToNearestIntegerScalar)}(Vector128, Vector128): {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/Sse41/RoundToNegativeInfinity.Double.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/RoundToNegativeInfinity.Double.cs new file mode 100644 index 000000000000..e8de8a03bdfe --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/RoundToNegativeInfinity.Double.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 RoundToNegativeInfinityDouble() + { + var test = new SimpleUnaryOpTest__RoundToNegativeInfinityDouble(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Sse2.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 (Sse2.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 (Sse2.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__RoundToNegativeInfinityDouble + { + private const int VectorSize = 16; + + private const int Op1ElementCount = VectorSize / sizeof(Double); + private const int RetElementCount = VectorSize / sizeof(Double); + + private static Double[] _data = new Double[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private SimpleUnaryOpTest__DataTable _dataTable; + + static SimpleUnaryOpTest__RoundToNegativeInfinityDouble() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (double)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), VectorSize); + } + + public SimpleUnaryOpTest__RoundToNegativeInfinityDouble() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (double)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), VectorSize); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (double)(random.NextDouble()); } + _dataTable = new SimpleUnaryOpTest__DataTable(_data, new Double[RetElementCount], VectorSize); + } + + public bool IsSupported => Sse41.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse41.RoundToNegativeInfinity( + Unsafe.Read>(_dataTable.inArrayPtr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse41.RoundToNegativeInfinity( + Sse2.LoadVector128((Double*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse41.RoundToNegativeInfinity( + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.RoundToNegativeInfinity), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.RoundToNegativeInfinity), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Double*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.RoundToNegativeInfinity), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse41.RoundToNegativeInfinity( + _clsVar + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = Sse41.RoundToNegativeInfinity(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var firstOp = Sse2.LoadVector128((Double*)(_dataTable.inArrayPtr)); + var result = Sse41.RoundToNegativeInfinity(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var firstOp = Sse2.LoadAlignedVector128((Double*)(_dataTable.inArrayPtr)); + var result = Sse41.RoundToNegativeInfinity(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleUnaryOpTest__RoundToNegativeInfinityDouble(); + var result = Sse41.RoundToNegativeInfinity(test._fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse41.RoundToNegativeInfinity(_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 firstOp, void* result, [CallerMemberName] string method = "") + { + Double[] inArray = new Double[Op1ElementCount]; + Double[] outArray = new Double[RetElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Double[] inArray = new Double[Op1ElementCount]; + Double[] outArray = new Double[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Double[] firstOp, Double[] result, [CallerMemberName] string method = "") + { + if (BitConverter.DoubleToInt64Bits(result[0]) != BitConverter.DoubleToInt64Bits(Math.Floor(firstOp[0]))) + { + Succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (BitConverter.DoubleToInt64Bits(result[i]) != BitConverter.DoubleToInt64Bits(Math.Floor(firstOp[i]))) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Sse41)}.{nameof(Sse41.RoundToNegativeInfinity)}(Vector128): {method} failed:"); + Console.WriteLine($" firstOp: ({string.Join(", ", firstOp)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse41/RoundToNegativeInfinity.Single.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/RoundToNegativeInfinity.Single.cs new file mode 100644 index 000000000000..1ec37c87217e --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/RoundToNegativeInfinity.Single.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 RoundToNegativeInfinitySingle() + { + var test = new SimpleUnaryOpTest__RoundToNegativeInfinitySingle(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Sse.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 (Sse.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 (Sse.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__RoundToNegativeInfinitySingle + { + private const int VectorSize = 16; + + private const int Op1ElementCount = VectorSize / sizeof(Single); + private const int RetElementCount = VectorSize / sizeof(Single); + + private static Single[] _data = new Single[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private SimpleUnaryOpTest__DataTable _dataTable; + + static SimpleUnaryOpTest__RoundToNegativeInfinitySingle() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (float)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), VectorSize); + } + + public SimpleUnaryOpTest__RoundToNegativeInfinitySingle() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (float)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), VectorSize); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (float)(random.NextDouble()); } + _dataTable = new SimpleUnaryOpTest__DataTable(_data, new Single[RetElementCount], VectorSize); + } + + public bool IsSupported => Sse41.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse41.RoundToNegativeInfinity( + Unsafe.Read>(_dataTable.inArrayPtr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse41.RoundToNegativeInfinity( + Sse.LoadVector128((Single*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse41.RoundToNegativeInfinity( + Sse.LoadAlignedVector128((Single*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.RoundToNegativeInfinity), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.RoundToNegativeInfinity), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadVector128((Single*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.RoundToNegativeInfinity), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadAlignedVector128((Single*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse41.RoundToNegativeInfinity( + _clsVar + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = Sse41.RoundToNegativeInfinity(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var firstOp = Sse.LoadVector128((Single*)(_dataTable.inArrayPtr)); + var result = Sse41.RoundToNegativeInfinity(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var firstOp = Sse.LoadAlignedVector128((Single*)(_dataTable.inArrayPtr)); + var result = Sse41.RoundToNegativeInfinity(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleUnaryOpTest__RoundToNegativeInfinitySingle(); + var result = Sse41.RoundToNegativeInfinity(test._fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse41.RoundToNegativeInfinity(_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 firstOp, void* result, [CallerMemberName] string method = "") + { + Single[] inArray = new Single[Op1ElementCount]; + Single[] outArray = new Single[RetElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Single[] inArray = new Single[Op1ElementCount]; + Single[] outArray = new Single[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Single[] firstOp, Single[] result, [CallerMemberName] string method = "") + { + if (BitConverter.SingleToInt32Bits(result[0]) != BitConverter.SingleToInt32Bits(MathF.Floor(firstOp[0]))) + { + Succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (BitConverter.SingleToInt32Bits(result[i]) != BitConverter.SingleToInt32Bits(MathF.Floor(firstOp[i]))) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Sse41)}.{nameof(Sse41.RoundToNegativeInfinity)}(Vector128): {method} failed:"); + Console.WriteLine($" firstOp: ({string.Join(", ", firstOp)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse41/RoundToNegativeInfinityScalar.Double.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/RoundToNegativeInfinityScalar.Double.cs new file mode 100644 index 000000000000..17bf996ff9b5 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/RoundToNegativeInfinityScalar.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 RoundToNegativeInfinityScalarDouble() + { + var test = new SimpleBinaryOpTest__RoundToNegativeInfinityScalarDouble(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Sse2.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 (Sse2.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 (Sse2.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__RoundToNegativeInfinityScalarDouble + { + private const int VectorSize = 16; + + 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 Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private SimpleBinaryOpTest__DataTable _dataTable; + + static SimpleBinaryOpTest__RoundToNegativeInfinityScalarDouble() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (double)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (double)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), VectorSize); + } + + public SimpleBinaryOpTest__RoundToNegativeInfinityScalarDouble() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (double)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (double)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(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(_data1, _data2, new Double[RetElementCount], VectorSize); + } + + public bool IsSupported => Sse41.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse41.RoundToNegativeInfinityScalar( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse41.RoundToNegativeInfinityScalar( + Sse2.LoadVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Double*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse41.RoundToNegativeInfinityScalar( + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.RoundToNegativeInfinityScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.RoundToNegativeInfinityScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Double*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.RoundToNegativeInfinityScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse41.RoundToNegativeInfinityScalar( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read>(_dataTable.inArray1Ptr); + var right = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = Sse41.RoundToNegativeInfinityScalar(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((Double*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((Double*)(_dataTable.inArray2Ptr)); + var result = Sse41.RoundToNegativeInfinityScalar(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray2Ptr)); + var result = Sse41.RoundToNegativeInfinityScalar(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__RoundToNegativeInfinityScalarDouble(); + var result = Sse41.RoundToNegativeInfinityScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse41.RoundToNegativeInfinityScalar(_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(Vector128 left, Vector128 right, void* result, [CallerMemberName] string method = "") + { + Double[] inArray1 = new Double[Op1ElementCount]; + Double[] inArray2 = new Double[Op2ElementCount]; + Double[] outArray = new Double[RetElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(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(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(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(Math.Floor(right[0]))) + { + Succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (BitConverter.DoubleToInt64Bits(result[i]) != BitConverter.DoubleToInt64Bits(left[i])) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Sse41)}.{nameof(Sse41.RoundToNegativeInfinityScalar)}(Vector128, Vector128): {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/Sse41/RoundToNegativeInfinityScalar.Single.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/RoundToNegativeInfinityScalar.Single.cs new file mode 100644 index 000000000000..cb10c0a22ca6 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/RoundToNegativeInfinityScalar.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 RoundToNegativeInfinityScalarSingle() + { + var test = new SimpleBinaryOpTest__RoundToNegativeInfinityScalarSingle(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Sse.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 (Sse.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 (Sse.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__RoundToNegativeInfinityScalarSingle + { + private const int VectorSize = 16; + + 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 Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private SimpleBinaryOpTest__DataTable _dataTable; + + static SimpleBinaryOpTest__RoundToNegativeInfinityScalarSingle() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (float)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (float)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), VectorSize); + } + + public SimpleBinaryOpTest__RoundToNegativeInfinityScalarSingle() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (float)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (float)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(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(_data1, _data2, new Single[RetElementCount], VectorSize); + } + + public bool IsSupported => Sse41.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse41.RoundToNegativeInfinityScalar( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse41.RoundToNegativeInfinityScalar( + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse41.RoundToNegativeInfinityScalar( + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.RoundToNegativeInfinityScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.RoundToNegativeInfinityScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.RoundToNegativeInfinityScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse41.RoundToNegativeInfinityScalar( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read>(_dataTable.inArray1Ptr); + var right = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = Sse41.RoundToNegativeInfinityScalar(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse41.RoundToNegativeInfinityScalar(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse41.RoundToNegativeInfinityScalar(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__RoundToNegativeInfinityScalarSingle(); + var result = Sse41.RoundToNegativeInfinityScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse41.RoundToNegativeInfinityScalar(_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(Vector128 left, Vector128 right, void* result, [CallerMemberName] string method = "") + { + Single[] inArray1 = new Single[Op1ElementCount]; + Single[] inArray2 = new Single[Op2ElementCount]; + Single[] outArray = new Single[RetElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(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(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(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(MathF.Floor(right[0]))) + { + Succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (BitConverter.SingleToInt32Bits(result[i]) != BitConverter.SingleToInt32Bits(left[i])) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Sse41)}.{nameof(Sse41.RoundToNegativeInfinityScalar)}(Vector128, Vector128): {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/Sse41/RoundToPositiveInfinity.Double.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/RoundToPositiveInfinity.Double.cs new file mode 100644 index 000000000000..02a2a21a5889 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/RoundToPositiveInfinity.Double.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 RoundToPositiveInfinityDouble() + { + var test = new SimpleUnaryOpTest__RoundToPositiveInfinityDouble(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Sse2.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 (Sse2.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 (Sse2.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__RoundToPositiveInfinityDouble + { + private const int VectorSize = 16; + + private const int Op1ElementCount = VectorSize / sizeof(Double); + private const int RetElementCount = VectorSize / sizeof(Double); + + private static Double[] _data = new Double[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private SimpleUnaryOpTest__DataTable _dataTable; + + static SimpleUnaryOpTest__RoundToPositiveInfinityDouble() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (double)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), VectorSize); + } + + public SimpleUnaryOpTest__RoundToPositiveInfinityDouble() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (double)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), VectorSize); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (double)(random.NextDouble()); } + _dataTable = new SimpleUnaryOpTest__DataTable(_data, new Double[RetElementCount], VectorSize); + } + + public bool IsSupported => Sse41.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse41.RoundToPositiveInfinity( + Unsafe.Read>(_dataTable.inArrayPtr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse41.RoundToPositiveInfinity( + Sse2.LoadVector128((Double*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse41.RoundToPositiveInfinity( + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.RoundToPositiveInfinity), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.RoundToPositiveInfinity), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Double*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.RoundToPositiveInfinity), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse41.RoundToPositiveInfinity( + _clsVar + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = Sse41.RoundToPositiveInfinity(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var firstOp = Sse2.LoadVector128((Double*)(_dataTable.inArrayPtr)); + var result = Sse41.RoundToPositiveInfinity(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var firstOp = Sse2.LoadAlignedVector128((Double*)(_dataTable.inArrayPtr)); + var result = Sse41.RoundToPositiveInfinity(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleUnaryOpTest__RoundToPositiveInfinityDouble(); + var result = Sse41.RoundToPositiveInfinity(test._fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse41.RoundToPositiveInfinity(_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 firstOp, void* result, [CallerMemberName] string method = "") + { + Double[] inArray = new Double[Op1ElementCount]; + Double[] outArray = new Double[RetElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Double[] inArray = new Double[Op1ElementCount]; + Double[] outArray = new Double[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Double[] firstOp, Double[] result, [CallerMemberName] string method = "") + { + if (BitConverter.DoubleToInt64Bits(result[0]) != BitConverter.DoubleToInt64Bits(Math.Ceiling(firstOp[0]))) + { + Succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (BitConverter.DoubleToInt64Bits(result[i]) != BitConverter.DoubleToInt64Bits(Math.Ceiling(firstOp[i]))) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Sse41)}.{nameof(Sse41.RoundToPositiveInfinity)}(Vector128): {method} failed:"); + Console.WriteLine($" firstOp: ({string.Join(", ", firstOp)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse41/RoundToPositiveInfinity.Single.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/RoundToPositiveInfinity.Single.cs new file mode 100644 index 000000000000..f2aefd81d45b --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/RoundToPositiveInfinity.Single.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 RoundToPositiveInfinitySingle() + { + var test = new SimpleUnaryOpTest__RoundToPositiveInfinitySingle(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Sse.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 (Sse.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 (Sse.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__RoundToPositiveInfinitySingle + { + private const int VectorSize = 16; + + private const int Op1ElementCount = VectorSize / sizeof(Single); + private const int RetElementCount = VectorSize / sizeof(Single); + + private static Single[] _data = new Single[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private SimpleUnaryOpTest__DataTable _dataTable; + + static SimpleUnaryOpTest__RoundToPositiveInfinitySingle() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (float)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), VectorSize); + } + + public SimpleUnaryOpTest__RoundToPositiveInfinitySingle() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (float)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), VectorSize); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (float)(random.NextDouble()); } + _dataTable = new SimpleUnaryOpTest__DataTable(_data, new Single[RetElementCount], VectorSize); + } + + public bool IsSupported => Sse41.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse41.RoundToPositiveInfinity( + Unsafe.Read>(_dataTable.inArrayPtr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse41.RoundToPositiveInfinity( + Sse.LoadVector128((Single*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse41.RoundToPositiveInfinity( + Sse.LoadAlignedVector128((Single*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.RoundToPositiveInfinity), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.RoundToPositiveInfinity), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadVector128((Single*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.RoundToPositiveInfinity), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadAlignedVector128((Single*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse41.RoundToPositiveInfinity( + _clsVar + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = Sse41.RoundToPositiveInfinity(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var firstOp = Sse.LoadVector128((Single*)(_dataTable.inArrayPtr)); + var result = Sse41.RoundToPositiveInfinity(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var firstOp = Sse.LoadAlignedVector128((Single*)(_dataTable.inArrayPtr)); + var result = Sse41.RoundToPositiveInfinity(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleUnaryOpTest__RoundToPositiveInfinitySingle(); + var result = Sse41.RoundToPositiveInfinity(test._fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse41.RoundToPositiveInfinity(_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 firstOp, void* result, [CallerMemberName] string method = "") + { + Single[] inArray = new Single[Op1ElementCount]; + Single[] outArray = new Single[RetElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Single[] inArray = new Single[Op1ElementCount]; + Single[] outArray = new Single[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Single[] firstOp, Single[] result, [CallerMemberName] string method = "") + { + if (BitConverter.SingleToInt32Bits(result[0]) != BitConverter.SingleToInt32Bits(MathF.Ceiling(firstOp[0]))) + { + Succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (BitConverter.SingleToInt32Bits(result[i]) != BitConverter.SingleToInt32Bits(MathF.Ceiling(firstOp[i]))) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Sse41)}.{nameof(Sse41.RoundToPositiveInfinity)}(Vector128): {method} failed:"); + Console.WriteLine($" firstOp: ({string.Join(", ", firstOp)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse41/RoundToPositiveInfinityScalar.Double.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/RoundToPositiveInfinityScalar.Double.cs new file mode 100644 index 000000000000..ed6e5df289aa --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/RoundToPositiveInfinityScalar.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 RoundToPositiveInfinityScalarDouble() + { + var test = new SimpleBinaryOpTest__RoundToPositiveInfinityScalarDouble(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Sse2.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 (Sse2.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 (Sse2.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__RoundToPositiveInfinityScalarDouble + { + private const int VectorSize = 16; + + 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 Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private SimpleBinaryOpTest__DataTable _dataTable; + + static SimpleBinaryOpTest__RoundToPositiveInfinityScalarDouble() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (double)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (double)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), VectorSize); + } + + public SimpleBinaryOpTest__RoundToPositiveInfinityScalarDouble() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (double)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (double)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(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(_data1, _data2, new Double[RetElementCount], VectorSize); + } + + public bool IsSupported => Sse41.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse41.RoundToPositiveInfinityScalar( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse41.RoundToPositiveInfinityScalar( + Sse2.LoadVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Double*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse41.RoundToPositiveInfinityScalar( + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.RoundToPositiveInfinityScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.RoundToPositiveInfinityScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Double*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.RoundToPositiveInfinityScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse41.RoundToPositiveInfinityScalar( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read>(_dataTable.inArray1Ptr); + var right = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = Sse41.RoundToPositiveInfinityScalar(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((Double*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((Double*)(_dataTable.inArray2Ptr)); + var result = Sse41.RoundToPositiveInfinityScalar(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray2Ptr)); + var result = Sse41.RoundToPositiveInfinityScalar(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__RoundToPositiveInfinityScalarDouble(); + var result = Sse41.RoundToPositiveInfinityScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse41.RoundToPositiveInfinityScalar(_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(Vector128 left, Vector128 right, void* result, [CallerMemberName] string method = "") + { + Double[] inArray1 = new Double[Op1ElementCount]; + Double[] inArray2 = new Double[Op2ElementCount]; + Double[] outArray = new Double[RetElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(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(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(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(Math.Ceiling(right[0]))) + { + Succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (BitConverter.DoubleToInt64Bits(result[i]) != BitConverter.DoubleToInt64Bits(left[i])) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Sse41)}.{nameof(Sse41.RoundToPositiveInfinityScalar)}(Vector128, Vector128): {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/Sse41/RoundToPositiveInfinityScalar.Single.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/RoundToPositiveInfinityScalar.Single.cs new file mode 100644 index 000000000000..87a81a74e0cf --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/RoundToPositiveInfinityScalar.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 RoundToPositiveInfinityScalarSingle() + { + var test = new SimpleBinaryOpTest__RoundToPositiveInfinityScalarSingle(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Sse.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 (Sse.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 (Sse.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__RoundToPositiveInfinityScalarSingle + { + private const int VectorSize = 16; + + 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 Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private SimpleBinaryOpTest__DataTable _dataTable; + + static SimpleBinaryOpTest__RoundToPositiveInfinityScalarSingle() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (float)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (float)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), VectorSize); + } + + public SimpleBinaryOpTest__RoundToPositiveInfinityScalarSingle() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (float)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (float)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(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(_data1, _data2, new Single[RetElementCount], VectorSize); + } + + public bool IsSupported => Sse41.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse41.RoundToPositiveInfinityScalar( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse41.RoundToPositiveInfinityScalar( + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse41.RoundToPositiveInfinityScalar( + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.RoundToPositiveInfinityScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.RoundToPositiveInfinityScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.RoundToPositiveInfinityScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse41.RoundToPositiveInfinityScalar( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read>(_dataTable.inArray1Ptr); + var right = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = Sse41.RoundToPositiveInfinityScalar(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse41.RoundToPositiveInfinityScalar(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse41.RoundToPositiveInfinityScalar(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__RoundToPositiveInfinityScalarSingle(); + var result = Sse41.RoundToPositiveInfinityScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse41.RoundToPositiveInfinityScalar(_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(Vector128 left, Vector128 right, void* result, [CallerMemberName] string method = "") + { + Single[] inArray1 = new Single[Op1ElementCount]; + Single[] inArray2 = new Single[Op2ElementCount]; + Single[] outArray = new Single[RetElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(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(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(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(MathF.Ceiling(right[0]))) + { + Succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (BitConverter.SingleToInt32Bits(result[i]) != BitConverter.SingleToInt32Bits(left[i])) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Sse41)}.{nameof(Sse41.RoundToPositiveInfinityScalar)}(Vector128, Vector128): {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/Sse41/RoundToZero.Double.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/RoundToZero.Double.cs new file mode 100644 index 000000000000..a0e82c70e02f --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/RoundToZero.Double.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 RoundToZeroDouble() + { + var test = new SimpleUnaryOpTest__RoundToZeroDouble(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Sse2.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 (Sse2.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 (Sse2.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__RoundToZeroDouble + { + private const int VectorSize = 16; + + private const int Op1ElementCount = VectorSize / sizeof(Double); + private const int RetElementCount = VectorSize / sizeof(Double); + + private static Double[] _data = new Double[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private SimpleUnaryOpTest__DataTable _dataTable; + + static SimpleUnaryOpTest__RoundToZeroDouble() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (double)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), VectorSize); + } + + public SimpleUnaryOpTest__RoundToZeroDouble() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (double)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), VectorSize); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (double)(random.NextDouble()); } + _dataTable = new SimpleUnaryOpTest__DataTable(_data, new Double[RetElementCount], VectorSize); + } + + public bool IsSupported => Sse41.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse41.RoundToZero( + Unsafe.Read>(_dataTable.inArrayPtr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse41.RoundToZero( + Sse2.LoadVector128((Double*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse41.RoundToZero( + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.RoundToZero), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.RoundToZero), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Double*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.RoundToZero), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse41.RoundToZero( + _clsVar + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = Sse41.RoundToZero(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var firstOp = Sse2.LoadVector128((Double*)(_dataTable.inArrayPtr)); + var result = Sse41.RoundToZero(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var firstOp = Sse2.LoadAlignedVector128((Double*)(_dataTable.inArrayPtr)); + var result = Sse41.RoundToZero(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleUnaryOpTest__RoundToZeroDouble(); + var result = Sse41.RoundToZero(test._fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse41.RoundToZero(_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 firstOp, void* result, [CallerMemberName] string method = "") + { + Double[] inArray = new Double[Op1ElementCount]; + Double[] outArray = new Double[RetElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Double[] inArray = new Double[Op1ElementCount]; + Double[] outArray = new Double[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Double[] firstOp, Double[] result, [CallerMemberName] string method = "") + { + if (BitConverter.DoubleToInt64Bits(result[0]) != BitConverter.DoubleToInt64Bits((firstOp[0] > 0) ? Math.Floor(firstOp[0]) : Math.Ceiling(firstOp[0]))) + { + Succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (BitConverter.DoubleToInt64Bits(result[i]) != BitConverter.DoubleToInt64Bits((firstOp[i] > 0) ? Math.Floor(firstOp[i]) : Math.Ceiling(firstOp[i]))) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Sse41)}.{nameof(Sse41.RoundToZero)}(Vector128): {method} failed:"); + Console.WriteLine($" firstOp: ({string.Join(", ", firstOp)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse41/RoundToZero.Single.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/RoundToZero.Single.cs new file mode 100644 index 000000000000..c85ab32ca5ba --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/RoundToZero.Single.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 RoundToZeroSingle() + { + var test = new SimpleUnaryOpTest__RoundToZeroSingle(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Sse.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 (Sse.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 (Sse.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__RoundToZeroSingle + { + private const int VectorSize = 16; + + private const int Op1ElementCount = VectorSize / sizeof(Single); + private const int RetElementCount = VectorSize / sizeof(Single); + + private static Single[] _data = new Single[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private SimpleUnaryOpTest__DataTable _dataTable; + + static SimpleUnaryOpTest__RoundToZeroSingle() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (float)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), VectorSize); + } + + public SimpleUnaryOpTest__RoundToZeroSingle() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (float)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), VectorSize); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (float)(random.NextDouble()); } + _dataTable = new SimpleUnaryOpTest__DataTable(_data, new Single[RetElementCount], VectorSize); + } + + public bool IsSupported => Sse41.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse41.RoundToZero( + Unsafe.Read>(_dataTable.inArrayPtr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse41.RoundToZero( + Sse.LoadVector128((Single*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse41.RoundToZero( + Sse.LoadAlignedVector128((Single*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.RoundToZero), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.RoundToZero), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadVector128((Single*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.RoundToZero), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadAlignedVector128((Single*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse41.RoundToZero( + _clsVar + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = Sse41.RoundToZero(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var firstOp = Sse.LoadVector128((Single*)(_dataTable.inArrayPtr)); + var result = Sse41.RoundToZero(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var firstOp = Sse.LoadAlignedVector128((Single*)(_dataTable.inArrayPtr)); + var result = Sse41.RoundToZero(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleUnaryOpTest__RoundToZeroSingle(); + var result = Sse41.RoundToZero(test._fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse41.RoundToZero(_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 firstOp, void* result, [CallerMemberName] string method = "") + { + Single[] inArray = new Single[Op1ElementCount]; + Single[] outArray = new Single[RetElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Single[] inArray = new Single[Op1ElementCount]; + Single[] outArray = new Single[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Single[] firstOp, Single[] result, [CallerMemberName] string method = "") + { + if (BitConverter.SingleToInt32Bits(result[0]) != BitConverter.SingleToInt32Bits((firstOp[0] > 0) ? MathF.Floor(firstOp[0]) : MathF.Ceiling(firstOp[0]))) + { + Succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (BitConverter.SingleToInt32Bits(result[i]) != BitConverter.SingleToInt32Bits((firstOp[i] > 0) ? MathF.Floor(firstOp[i]) : MathF.Ceiling(firstOp[i]))) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Sse41)}.{nameof(Sse41.RoundToZero)}(Vector128): {method} failed:"); + Console.WriteLine($" firstOp: ({string.Join(", ", firstOp)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse41/RoundToZeroScalar.Double.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/RoundToZeroScalar.Double.cs new file mode 100644 index 000000000000..4919a390f6e9 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/RoundToZeroScalar.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 RoundToZeroScalarDouble() + { + var test = new SimpleBinaryOpTest__RoundToZeroScalarDouble(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Sse2.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 (Sse2.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 (Sse2.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__RoundToZeroScalarDouble + { + private const int VectorSize = 16; + + 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 Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private SimpleBinaryOpTest__DataTable _dataTable; + + static SimpleBinaryOpTest__RoundToZeroScalarDouble() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (double)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (double)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), VectorSize); + } + + public SimpleBinaryOpTest__RoundToZeroScalarDouble() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (double)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (double)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(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(_data1, _data2, new Double[RetElementCount], VectorSize); + } + + public bool IsSupported => Sse41.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse41.RoundToZeroScalar( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse41.RoundToZeroScalar( + Sse2.LoadVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Double*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse41.RoundToZeroScalar( + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.RoundToZeroScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.RoundToZeroScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Double*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.RoundToZeroScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse41.RoundToZeroScalar( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read>(_dataTable.inArray1Ptr); + var right = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = Sse41.RoundToZeroScalar(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((Double*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((Double*)(_dataTable.inArray2Ptr)); + var result = Sse41.RoundToZeroScalar(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray2Ptr)); + var result = Sse41.RoundToZeroScalar(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__RoundToZeroScalarDouble(); + var result = Sse41.RoundToZeroScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse41.RoundToZeroScalar(_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(Vector128 left, Vector128 right, void* result, [CallerMemberName] string method = "") + { + Double[] inArray1 = new Double[Op1ElementCount]; + Double[] inArray2 = new Double[Op2ElementCount]; + Double[] outArray = new Double[RetElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(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(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(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] > 0) ? Math.Floor(right[0]) : Math.Ceiling(right[0]))) + { + Succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (BitConverter.DoubleToInt64Bits(result[i]) != BitConverter.DoubleToInt64Bits(left[i])) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Sse41)}.{nameof(Sse41.RoundToZeroScalar)}(Vector128, Vector128): {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/Sse41/RoundToZeroScalar.Single.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/RoundToZeroScalar.Single.cs new file mode 100644 index 000000000000..a56aad9b5d71 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/RoundToZeroScalar.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 RoundToZeroScalarSingle() + { + var test = new SimpleBinaryOpTest__RoundToZeroScalarSingle(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Sse.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 (Sse.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 (Sse.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__RoundToZeroScalarSingle + { + private const int VectorSize = 16; + + 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 Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private SimpleBinaryOpTest__DataTable _dataTable; + + static SimpleBinaryOpTest__RoundToZeroScalarSingle() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (float)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (float)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), VectorSize); + } + + public SimpleBinaryOpTest__RoundToZeroScalarSingle() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (float)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (float)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(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(_data1, _data2, new Single[RetElementCount], VectorSize); + } + + public bool IsSupported => Sse41.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse41.RoundToZeroScalar( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse41.RoundToZeroScalar( + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse41.RoundToZeroScalar( + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.RoundToZeroScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.RoundToZeroScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.RoundToZeroScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse41.RoundToZeroScalar( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read>(_dataTable.inArray1Ptr); + var right = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = Sse41.RoundToZeroScalar(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse41.RoundToZeroScalar(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse41.RoundToZeroScalar(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__RoundToZeroScalarSingle(); + var result = Sse41.RoundToZeroScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse41.RoundToZeroScalar(_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(Vector128 left, Vector128 right, void* result, [CallerMemberName] string method = "") + { + Single[] inArray1 = new Single[Op1ElementCount]; + Single[] inArray2 = new Single[Op2ElementCount]; + Single[] outArray = new Single[RetElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(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(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(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] > 0) ? MathF.Floor(right[0]) : MathF.Ceiling(right[0]))) + { + Succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (BitConverter.SingleToInt32Bits(result[i]) != BitConverter.SingleToInt32Bits(left[i])) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Sse41)}.{nameof(Sse41.RoundToZeroScalar)}(Vector128, Vector128): {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/Sse41/Sse41_r.csproj b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/Sse41_r.csproj index 3ca03a2627d9..158e94a27d23 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse41/Sse41_r.csproj +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/Sse41_r.csproj @@ -27,12 +27,107 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + + diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse41/Sse41_ro.csproj b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/Sse41_ro.csproj index 93a8455c564e..74dcfa091e7e 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse41/Sse41_ro.csproj +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/Sse41_ro.csproj @@ -27,12 +27,107 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + + diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestAllOnes.Byte.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestAllOnes.Byte.cs new file mode 100644 index 000000000000..6157c244dc6c --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestAllOnes.Byte.cs @@ -0,0 +1,283 @@ +// 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.Linq; +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 TestAllOnesByte() + { + var test = new BooleanComparisonOpTest__TestAllOnesByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Sse2.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 (Sse2.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 (Sse2.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 BooleanComparisonOpTest__TestAllOnesByte + { + private const int VectorSize = 16; + + private const int Op1ElementCount = VectorSize / sizeof(Byte); + + private static Byte[] _data = new Byte[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private BooleanUnaryOpTest__DataTable _dataTable; + + static BooleanComparisonOpTest__TestAllOnesByte() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (byte)(random.Next(0, byte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), VectorSize); + } + + public BooleanComparisonOpTest__TestAllOnesByte() + { + 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, byte>(ref _fld), ref Unsafe.As(ref _data[0]), VectorSize); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (byte)(random.Next(0, byte.MaxValue)); } + _dataTable = new BooleanUnaryOpTest__DataTable(_data, VectorSize); + } + + public bool IsSupported => Sse41.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse41.TestAllOnes( + Unsafe.Read>(_dataTable.inArrayPtr) + ); + + ValidateResult(_dataTable.inArrayPtr, result); + } + + public void RunBasicScenario_Load() + { + var result = Sse41.TestAllOnes( + Sse2.LoadVector128((Byte*)(_dataTable.inArrayPtr)) + ); + + ValidateResult(_dataTable.inArrayPtr, result); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse41.TestAllOnes( + Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArrayPtr)) + ); + + ValidateResult(_dataTable.inArrayPtr, result); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestAllOnes), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr) + }); + + ValidateResult(_dataTable.inArrayPtr, (bool)(result)); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestAllOnes), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Byte*)(_dataTable.inArrayPtr)) + }); + + ValidateResult(_dataTable.inArrayPtr, (bool)(result)); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestAllOnes), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArrayPtr)) + }); + + ValidateResult(_dataTable.inArrayPtr, (bool)(result)); + } + + public void RunClsVarScenario() + { + var result = Sse41.TestAllOnes( + _clsVar + ); + + ValidateResult(_clsVar, result); + } + + public void RunLclVarScenario_UnsafeRead() + { + var value = Unsafe.Read>(_dataTable.inArrayPtr); + var result = Sse41.TestAllOnes(value); + + ValidateResult(value, result); + } + + public void RunLclVarScenario_Load() + { + var value = Sse2.LoadVector128((Byte*)(_dataTable.inArrayPtr)); + var result = Sse41.TestAllOnes(value); + + ValidateResult(value, result); + } + + public void RunLclVarScenario_LoadAligned() + { + var value = Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArrayPtr)); + var result = Sse41.TestAllOnes(value); + + ValidateResult(value, result); + } + + public void RunLclFldScenario() + { + var test = new BooleanComparisonOpTest__TestAllOnesByte(); + var result = Sse41.TestAllOnes(test._fld); + + ValidateResult(test._fld, result); + } + + public void RunFldScenario() + { + var result = Sse41.TestAllOnes(_fld); + + ValidateResult(_fld, result); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128 value, bool result, [CallerMemberName] string method = "") + { + Byte[] inArray = new Byte[Op1ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray[0]), value); + + ValidateResult(inArray, result, method); + } + + private void ValidateResult(void* value, bool result, [CallerMemberName] string method = "") + { + Byte[] inArray = new Byte[Op1ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(value), VectorSize); + + ValidateResult(inArray, result, method); + } + + private void ValidateResult(Byte[] value, bool result, [CallerMemberName] string method = "") + { + var expectedResult = true; + + for (var i = 0; i < Op1ElementCount; i++) + { + expectedResult &= ((~value[i] & byte.MaxValue) == 0); + } + + if (expectedResult != result) + { + Succeeded = false; + + Console.WriteLine($"{nameof(Sse41)}.{nameof(Sse41.TestAllOnes)}(Vector128): {method} failed:"); + Console.WriteLine($" value: ({string.Join(", ", value)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestAllOnes.Int16.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestAllOnes.Int16.cs new file mode 100644 index 000000000000..23841864cb63 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestAllOnes.Int16.cs @@ -0,0 +1,283 @@ +// 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.Linq; +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 TestAllOnesInt16() + { + var test = new BooleanComparisonOpTest__TestAllOnesInt16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Sse2.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 (Sse2.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 (Sse2.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 BooleanComparisonOpTest__TestAllOnesInt16 + { + private const int VectorSize = 16; + + private const int Op1ElementCount = VectorSize / sizeof(Int16); + + private static Int16[] _data = new Int16[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private BooleanUnaryOpTest__DataTable _dataTable; + + static BooleanComparisonOpTest__TestAllOnesInt16() + { + 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, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), VectorSize); + } + + public BooleanComparisonOpTest__TestAllOnesInt16() + { + 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, byte>(ref _fld), ref Unsafe.As(ref _data[0]), VectorSize); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (short)(random.Next(short.MinValue, short.MaxValue)); } + _dataTable = new BooleanUnaryOpTest__DataTable(_data, VectorSize); + } + + public bool IsSupported => Sse41.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse41.TestAllOnes( + Unsafe.Read>(_dataTable.inArrayPtr) + ); + + ValidateResult(_dataTable.inArrayPtr, result); + } + + public void RunBasicScenario_Load() + { + var result = Sse41.TestAllOnes( + Sse2.LoadVector128((Int16*)(_dataTable.inArrayPtr)) + ); + + ValidateResult(_dataTable.inArrayPtr, result); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse41.TestAllOnes( + Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArrayPtr)) + ); + + ValidateResult(_dataTable.inArrayPtr, result); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestAllOnes), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr) + }); + + ValidateResult(_dataTable.inArrayPtr, (bool)(result)); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestAllOnes), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Int16*)(_dataTable.inArrayPtr)) + }); + + ValidateResult(_dataTable.inArrayPtr, (bool)(result)); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestAllOnes), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArrayPtr)) + }); + + ValidateResult(_dataTable.inArrayPtr, (bool)(result)); + } + + public void RunClsVarScenario() + { + var result = Sse41.TestAllOnes( + _clsVar + ); + + ValidateResult(_clsVar, result); + } + + public void RunLclVarScenario_UnsafeRead() + { + var value = Unsafe.Read>(_dataTable.inArrayPtr); + var result = Sse41.TestAllOnes(value); + + ValidateResult(value, result); + } + + public void RunLclVarScenario_Load() + { + var value = Sse2.LoadVector128((Int16*)(_dataTable.inArrayPtr)); + var result = Sse41.TestAllOnes(value); + + ValidateResult(value, result); + } + + public void RunLclVarScenario_LoadAligned() + { + var value = Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArrayPtr)); + var result = Sse41.TestAllOnes(value); + + ValidateResult(value, result); + } + + public void RunLclFldScenario() + { + var test = new BooleanComparisonOpTest__TestAllOnesInt16(); + var result = Sse41.TestAllOnes(test._fld); + + ValidateResult(test._fld, result); + } + + public void RunFldScenario() + { + var result = Sse41.TestAllOnes(_fld); + + ValidateResult(_fld, result); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128 value, bool result, [CallerMemberName] string method = "") + { + Int16[] inArray = new Int16[Op1ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray[0]), value); + + ValidateResult(inArray, result, method); + } + + private void ValidateResult(void* value, bool result, [CallerMemberName] string method = "") + { + Int16[] inArray = new Int16[Op1ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(value), VectorSize); + + ValidateResult(inArray, result, method); + } + + private void ValidateResult(Int16[] value, bool result, [CallerMemberName] string method = "") + { + var expectedResult = true; + + for (var i = 0; i < Op1ElementCount; i++) + { + expectedResult &= ((~value[i] & -1) == 0); + } + + if (expectedResult != result) + { + Succeeded = false; + + Console.WriteLine($"{nameof(Sse41)}.{nameof(Sse41.TestAllOnes)}(Vector128): {method} failed:"); + Console.WriteLine($" value: ({string.Join(", ", value)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestAllOnes.Int32.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestAllOnes.Int32.cs new file mode 100644 index 000000000000..2cbbbf520120 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestAllOnes.Int32.cs @@ -0,0 +1,283 @@ +// 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.Linq; +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 TestAllOnesInt32() + { + var test = new BooleanComparisonOpTest__TestAllOnesInt32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Sse2.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 (Sse2.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 (Sse2.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 BooleanComparisonOpTest__TestAllOnesInt32 + { + private const int VectorSize = 16; + + private const int Op1ElementCount = VectorSize / sizeof(Int32); + + private static Int32[] _data = new Int32[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private BooleanUnaryOpTest__DataTable _dataTable; + + static BooleanComparisonOpTest__TestAllOnesInt32() + { + 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, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), VectorSize); + } + + public BooleanComparisonOpTest__TestAllOnesInt32() + { + 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, byte>(ref _fld), ref Unsafe.As(ref _data[0]), VectorSize); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (int)(random.Next(int.MinValue, int.MaxValue)); } + _dataTable = new BooleanUnaryOpTest__DataTable(_data, VectorSize); + } + + public bool IsSupported => Sse41.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse41.TestAllOnes( + Unsafe.Read>(_dataTable.inArrayPtr) + ); + + ValidateResult(_dataTable.inArrayPtr, result); + } + + public void RunBasicScenario_Load() + { + var result = Sse41.TestAllOnes( + Sse2.LoadVector128((Int32*)(_dataTable.inArrayPtr)) + ); + + ValidateResult(_dataTable.inArrayPtr, result); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse41.TestAllOnes( + Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArrayPtr)) + ); + + ValidateResult(_dataTable.inArrayPtr, result); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestAllOnes), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr) + }); + + ValidateResult(_dataTable.inArrayPtr, (bool)(result)); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestAllOnes), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Int32*)(_dataTable.inArrayPtr)) + }); + + ValidateResult(_dataTable.inArrayPtr, (bool)(result)); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestAllOnes), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArrayPtr)) + }); + + ValidateResult(_dataTable.inArrayPtr, (bool)(result)); + } + + public void RunClsVarScenario() + { + var result = Sse41.TestAllOnes( + _clsVar + ); + + ValidateResult(_clsVar, result); + } + + public void RunLclVarScenario_UnsafeRead() + { + var value = Unsafe.Read>(_dataTable.inArrayPtr); + var result = Sse41.TestAllOnes(value); + + ValidateResult(value, result); + } + + public void RunLclVarScenario_Load() + { + var value = Sse2.LoadVector128((Int32*)(_dataTable.inArrayPtr)); + var result = Sse41.TestAllOnes(value); + + ValidateResult(value, result); + } + + public void RunLclVarScenario_LoadAligned() + { + var value = Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArrayPtr)); + var result = Sse41.TestAllOnes(value); + + ValidateResult(value, result); + } + + public void RunLclFldScenario() + { + var test = new BooleanComparisonOpTest__TestAllOnesInt32(); + var result = Sse41.TestAllOnes(test._fld); + + ValidateResult(test._fld, result); + } + + public void RunFldScenario() + { + var result = Sse41.TestAllOnes(_fld); + + ValidateResult(_fld, result); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128 value, bool result, [CallerMemberName] string method = "") + { + Int32[] inArray = new Int32[Op1ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray[0]), value); + + ValidateResult(inArray, result, method); + } + + private void ValidateResult(void* value, bool result, [CallerMemberName] string method = "") + { + Int32[] inArray = new Int32[Op1ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(value), VectorSize); + + ValidateResult(inArray, result, method); + } + + private void ValidateResult(Int32[] value, bool result, [CallerMemberName] string method = "") + { + var expectedResult = true; + + for (var i = 0; i < Op1ElementCount; i++) + { + expectedResult &= ((~value[i] & -1) == 0); + } + + if (expectedResult != result) + { + Succeeded = false; + + Console.WriteLine($"{nameof(Sse41)}.{nameof(Sse41.TestAllOnes)}(Vector128): {method} failed:"); + Console.WriteLine($" value: ({string.Join(", ", value)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestAllOnes.Int64.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestAllOnes.Int64.cs new file mode 100644 index 000000000000..4c0891f5bf9c --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestAllOnes.Int64.cs @@ -0,0 +1,283 @@ +// 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.Linq; +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 TestAllOnesInt64() + { + var test = new BooleanComparisonOpTest__TestAllOnesInt64(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Sse2.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 (Sse2.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 (Sse2.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 BooleanComparisonOpTest__TestAllOnesInt64 + { + private const int VectorSize = 16; + + private const int Op1ElementCount = VectorSize / sizeof(Int64); + + private static Int64[] _data = new Int64[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private BooleanUnaryOpTest__DataTable _dataTable; + + static BooleanComparisonOpTest__TestAllOnesInt64() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (long)(random.Next(int.MinValue, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), VectorSize); + } + + public BooleanComparisonOpTest__TestAllOnesInt64() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (long)(random.Next(int.MinValue, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), VectorSize); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (long)(random.Next(int.MinValue, int.MaxValue)); } + _dataTable = new BooleanUnaryOpTest__DataTable(_data, VectorSize); + } + + public bool IsSupported => Sse41.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse41.TestAllOnes( + Unsafe.Read>(_dataTable.inArrayPtr) + ); + + ValidateResult(_dataTable.inArrayPtr, result); + } + + public void RunBasicScenario_Load() + { + var result = Sse41.TestAllOnes( + Sse2.LoadVector128((Int64*)(_dataTable.inArrayPtr)) + ); + + ValidateResult(_dataTable.inArrayPtr, result); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse41.TestAllOnes( + Sse2.LoadAlignedVector128((Int64*)(_dataTable.inArrayPtr)) + ); + + ValidateResult(_dataTable.inArrayPtr, result); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestAllOnes), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr) + }); + + ValidateResult(_dataTable.inArrayPtr, (bool)(result)); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestAllOnes), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Int64*)(_dataTable.inArrayPtr)) + }); + + ValidateResult(_dataTable.inArrayPtr, (bool)(result)); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestAllOnes), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Int64*)(_dataTable.inArrayPtr)) + }); + + ValidateResult(_dataTable.inArrayPtr, (bool)(result)); + } + + public void RunClsVarScenario() + { + var result = Sse41.TestAllOnes( + _clsVar + ); + + ValidateResult(_clsVar, result); + } + + public void RunLclVarScenario_UnsafeRead() + { + var value = Unsafe.Read>(_dataTable.inArrayPtr); + var result = Sse41.TestAllOnes(value); + + ValidateResult(value, result); + } + + public void RunLclVarScenario_Load() + { + var value = Sse2.LoadVector128((Int64*)(_dataTable.inArrayPtr)); + var result = Sse41.TestAllOnes(value); + + ValidateResult(value, result); + } + + public void RunLclVarScenario_LoadAligned() + { + var value = Sse2.LoadAlignedVector128((Int64*)(_dataTable.inArrayPtr)); + var result = Sse41.TestAllOnes(value); + + ValidateResult(value, result); + } + + public void RunLclFldScenario() + { + var test = new BooleanComparisonOpTest__TestAllOnesInt64(); + var result = Sse41.TestAllOnes(test._fld); + + ValidateResult(test._fld, result); + } + + public void RunFldScenario() + { + var result = Sse41.TestAllOnes(_fld); + + ValidateResult(_fld, result); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128 value, bool result, [CallerMemberName] string method = "") + { + Int64[] inArray = new Int64[Op1ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray[0]), value); + + ValidateResult(inArray, result, method); + } + + private void ValidateResult(void* value, bool result, [CallerMemberName] string method = "") + { + Int64[] inArray = new Int64[Op1ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(value), VectorSize); + + ValidateResult(inArray, result, method); + } + + private void ValidateResult(Int64[] value, bool result, [CallerMemberName] string method = "") + { + var expectedResult = true; + + for (var i = 0; i < Op1ElementCount; i++) + { + expectedResult &= ((~value[i] & -1) == 0); + } + + if (expectedResult != result) + { + Succeeded = false; + + Console.WriteLine($"{nameof(Sse41)}.{nameof(Sse41.TestAllOnes)}(Vector128): {method} failed:"); + Console.WriteLine($" value: ({string.Join(", ", value)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestAllOnes.SByte.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestAllOnes.SByte.cs new file mode 100644 index 000000000000..df3f3b8c89f2 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestAllOnes.SByte.cs @@ -0,0 +1,283 @@ +// 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.Linq; +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 TestAllOnesSByte() + { + var test = new BooleanComparisonOpTest__TestAllOnesSByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Sse2.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 (Sse2.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 (Sse2.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 BooleanComparisonOpTest__TestAllOnesSByte + { + private const int VectorSize = 16; + + private const int Op1ElementCount = VectorSize / sizeof(SByte); + + private static SByte[] _data = new SByte[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private BooleanUnaryOpTest__DataTable _dataTable; + + static BooleanComparisonOpTest__TestAllOnesSByte() + { + 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, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), VectorSize); + } + + public BooleanComparisonOpTest__TestAllOnesSByte() + { + 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, byte>(ref _fld), ref Unsafe.As(ref _data[0]), VectorSize); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue)); } + _dataTable = new BooleanUnaryOpTest__DataTable(_data, VectorSize); + } + + public bool IsSupported => Sse41.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse41.TestAllOnes( + Unsafe.Read>(_dataTable.inArrayPtr) + ); + + ValidateResult(_dataTable.inArrayPtr, result); + } + + public void RunBasicScenario_Load() + { + var result = Sse41.TestAllOnes( + Sse2.LoadVector128((SByte*)(_dataTable.inArrayPtr)) + ); + + ValidateResult(_dataTable.inArrayPtr, result); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse41.TestAllOnes( + Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArrayPtr)) + ); + + ValidateResult(_dataTable.inArrayPtr, result); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestAllOnes), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr) + }); + + ValidateResult(_dataTable.inArrayPtr, (bool)(result)); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestAllOnes), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((SByte*)(_dataTable.inArrayPtr)) + }); + + ValidateResult(_dataTable.inArrayPtr, (bool)(result)); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestAllOnes), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArrayPtr)) + }); + + ValidateResult(_dataTable.inArrayPtr, (bool)(result)); + } + + public void RunClsVarScenario() + { + var result = Sse41.TestAllOnes( + _clsVar + ); + + ValidateResult(_clsVar, result); + } + + public void RunLclVarScenario_UnsafeRead() + { + var value = Unsafe.Read>(_dataTable.inArrayPtr); + var result = Sse41.TestAllOnes(value); + + ValidateResult(value, result); + } + + public void RunLclVarScenario_Load() + { + var value = Sse2.LoadVector128((SByte*)(_dataTable.inArrayPtr)); + var result = Sse41.TestAllOnes(value); + + ValidateResult(value, result); + } + + public void RunLclVarScenario_LoadAligned() + { + var value = Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArrayPtr)); + var result = Sse41.TestAllOnes(value); + + ValidateResult(value, result); + } + + public void RunLclFldScenario() + { + var test = new BooleanComparisonOpTest__TestAllOnesSByte(); + var result = Sse41.TestAllOnes(test._fld); + + ValidateResult(test._fld, result); + } + + public void RunFldScenario() + { + var result = Sse41.TestAllOnes(_fld); + + ValidateResult(_fld, result); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128 value, bool result, [CallerMemberName] string method = "") + { + SByte[] inArray = new SByte[Op1ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray[0]), value); + + ValidateResult(inArray, result, method); + } + + private void ValidateResult(void* value, bool result, [CallerMemberName] string method = "") + { + SByte[] inArray = new SByte[Op1ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(value), VectorSize); + + ValidateResult(inArray, result, method); + } + + private void ValidateResult(SByte[] value, bool result, [CallerMemberName] string method = "") + { + var expectedResult = true; + + for (var i = 0; i < Op1ElementCount; i++) + { + expectedResult &= ((~value[i] & -1) == 0); + } + + if (expectedResult != result) + { + Succeeded = false; + + Console.WriteLine($"{nameof(Sse41)}.{nameof(Sse41.TestAllOnes)}(Vector128): {method} failed:"); + Console.WriteLine($" value: ({string.Join(", ", value)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestAllOnes.UInt16.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestAllOnes.UInt16.cs new file mode 100644 index 000000000000..cb9a8d7c2276 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestAllOnes.UInt16.cs @@ -0,0 +1,283 @@ +// 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.Linq; +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 TestAllOnesUInt16() + { + var test = new BooleanComparisonOpTest__TestAllOnesUInt16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Sse2.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 (Sse2.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 (Sse2.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 BooleanComparisonOpTest__TestAllOnesUInt16 + { + private const int VectorSize = 16; + + private const int Op1ElementCount = VectorSize / sizeof(UInt16); + + private static UInt16[] _data = new UInt16[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private BooleanUnaryOpTest__DataTable _dataTable; + + static BooleanComparisonOpTest__TestAllOnesUInt16() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (ushort)(random.Next(0, ushort.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), VectorSize); + } + + public BooleanComparisonOpTest__TestAllOnesUInt16() + { + 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, byte>(ref _fld), ref Unsafe.As(ref _data[0]), VectorSize); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (ushort)(random.Next(0, ushort.MaxValue)); } + _dataTable = new BooleanUnaryOpTest__DataTable(_data, VectorSize); + } + + public bool IsSupported => Sse41.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse41.TestAllOnes( + Unsafe.Read>(_dataTable.inArrayPtr) + ); + + ValidateResult(_dataTable.inArrayPtr, result); + } + + public void RunBasicScenario_Load() + { + var result = Sse41.TestAllOnes( + Sse2.LoadVector128((UInt16*)(_dataTable.inArrayPtr)) + ); + + ValidateResult(_dataTable.inArrayPtr, result); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse41.TestAllOnes( + Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArrayPtr)) + ); + + ValidateResult(_dataTable.inArrayPtr, result); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestAllOnes), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr) + }); + + ValidateResult(_dataTable.inArrayPtr, (bool)(result)); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestAllOnes), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((UInt16*)(_dataTable.inArrayPtr)) + }); + + ValidateResult(_dataTable.inArrayPtr, (bool)(result)); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestAllOnes), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArrayPtr)) + }); + + ValidateResult(_dataTable.inArrayPtr, (bool)(result)); + } + + public void RunClsVarScenario() + { + var result = Sse41.TestAllOnes( + _clsVar + ); + + ValidateResult(_clsVar, result); + } + + public void RunLclVarScenario_UnsafeRead() + { + var value = Unsafe.Read>(_dataTable.inArrayPtr); + var result = Sse41.TestAllOnes(value); + + ValidateResult(value, result); + } + + public void RunLclVarScenario_Load() + { + var value = Sse2.LoadVector128((UInt16*)(_dataTable.inArrayPtr)); + var result = Sse41.TestAllOnes(value); + + ValidateResult(value, result); + } + + public void RunLclVarScenario_LoadAligned() + { + var value = Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArrayPtr)); + var result = Sse41.TestAllOnes(value); + + ValidateResult(value, result); + } + + public void RunLclFldScenario() + { + var test = new BooleanComparisonOpTest__TestAllOnesUInt16(); + var result = Sse41.TestAllOnes(test._fld); + + ValidateResult(test._fld, result); + } + + public void RunFldScenario() + { + var result = Sse41.TestAllOnes(_fld); + + ValidateResult(_fld, result); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128 value, bool result, [CallerMemberName] string method = "") + { + UInt16[] inArray = new UInt16[Op1ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray[0]), value); + + ValidateResult(inArray, result, method); + } + + private void ValidateResult(void* value, bool result, [CallerMemberName] string method = "") + { + UInt16[] inArray = new UInt16[Op1ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(value), VectorSize); + + ValidateResult(inArray, result, method); + } + + private void ValidateResult(UInt16[] value, bool result, [CallerMemberName] string method = "") + { + var expectedResult = true; + + for (var i = 0; i < Op1ElementCount; i++) + { + expectedResult &= ((~value[i] & ushort.MaxValue) == 0); + } + + if (expectedResult != result) + { + Succeeded = false; + + Console.WriteLine($"{nameof(Sse41)}.{nameof(Sse41.TestAllOnes)}(Vector128): {method} failed:"); + Console.WriteLine($" value: ({string.Join(", ", value)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestAllOnes.UInt32.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestAllOnes.UInt32.cs new file mode 100644 index 000000000000..f2ff4be8bc2e --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestAllOnes.UInt32.cs @@ -0,0 +1,283 @@ +// 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.Linq; +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 TestAllOnesUInt32() + { + var test = new BooleanComparisonOpTest__TestAllOnesUInt32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Sse2.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 (Sse2.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 (Sse2.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 BooleanComparisonOpTest__TestAllOnesUInt32 + { + private const int VectorSize = 16; + + private const int Op1ElementCount = VectorSize / sizeof(UInt32); + + private static UInt32[] _data = new UInt32[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private BooleanUnaryOpTest__DataTable _dataTable; + + static BooleanComparisonOpTest__TestAllOnesUInt32() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (uint)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), VectorSize); + } + + public BooleanComparisonOpTest__TestAllOnesUInt32() + { + 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, byte>(ref _fld), ref Unsafe.As(ref _data[0]), VectorSize); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (uint)(random.Next(0, int.MaxValue)); } + _dataTable = new BooleanUnaryOpTest__DataTable(_data, VectorSize); + } + + public bool IsSupported => Sse41.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse41.TestAllOnes( + Unsafe.Read>(_dataTable.inArrayPtr) + ); + + ValidateResult(_dataTable.inArrayPtr, result); + } + + public void RunBasicScenario_Load() + { + var result = Sse41.TestAllOnes( + Sse2.LoadVector128((UInt32*)(_dataTable.inArrayPtr)) + ); + + ValidateResult(_dataTable.inArrayPtr, result); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse41.TestAllOnes( + Sse2.LoadAlignedVector128((UInt32*)(_dataTable.inArrayPtr)) + ); + + ValidateResult(_dataTable.inArrayPtr, result); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestAllOnes), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr) + }); + + ValidateResult(_dataTable.inArrayPtr, (bool)(result)); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestAllOnes), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((UInt32*)(_dataTable.inArrayPtr)) + }); + + ValidateResult(_dataTable.inArrayPtr, (bool)(result)); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestAllOnes), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((UInt32*)(_dataTable.inArrayPtr)) + }); + + ValidateResult(_dataTable.inArrayPtr, (bool)(result)); + } + + public void RunClsVarScenario() + { + var result = Sse41.TestAllOnes( + _clsVar + ); + + ValidateResult(_clsVar, result); + } + + public void RunLclVarScenario_UnsafeRead() + { + var value = Unsafe.Read>(_dataTable.inArrayPtr); + var result = Sse41.TestAllOnes(value); + + ValidateResult(value, result); + } + + public void RunLclVarScenario_Load() + { + var value = Sse2.LoadVector128((UInt32*)(_dataTable.inArrayPtr)); + var result = Sse41.TestAllOnes(value); + + ValidateResult(value, result); + } + + public void RunLclVarScenario_LoadAligned() + { + var value = Sse2.LoadAlignedVector128((UInt32*)(_dataTable.inArrayPtr)); + var result = Sse41.TestAllOnes(value); + + ValidateResult(value, result); + } + + public void RunLclFldScenario() + { + var test = new BooleanComparisonOpTest__TestAllOnesUInt32(); + var result = Sse41.TestAllOnes(test._fld); + + ValidateResult(test._fld, result); + } + + public void RunFldScenario() + { + var result = Sse41.TestAllOnes(_fld); + + ValidateResult(_fld, result); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128 value, bool result, [CallerMemberName] string method = "") + { + UInt32[] inArray = new UInt32[Op1ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray[0]), value); + + ValidateResult(inArray, result, method); + } + + private void ValidateResult(void* value, bool result, [CallerMemberName] string method = "") + { + UInt32[] inArray = new UInt32[Op1ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(value), VectorSize); + + ValidateResult(inArray, result, method); + } + + private void ValidateResult(UInt32[] value, bool result, [CallerMemberName] string method = "") + { + var expectedResult = true; + + for (var i = 0; i < Op1ElementCount; i++) + { + expectedResult &= ((~value[i] & uint.MaxValue) == 0); + } + + if (expectedResult != result) + { + Succeeded = false; + + Console.WriteLine($"{nameof(Sse41)}.{nameof(Sse41.TestAllOnes)}(Vector128): {method} failed:"); + Console.WriteLine($" value: ({string.Join(", ", value)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestAllOnes.UInt64.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestAllOnes.UInt64.cs new file mode 100644 index 000000000000..5b8c89c87ef6 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestAllOnes.UInt64.cs @@ -0,0 +1,283 @@ +// 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.Linq; +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 TestAllOnesUInt64() + { + var test = new BooleanComparisonOpTest__TestAllOnesUInt64(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Sse2.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 (Sse2.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 (Sse2.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 BooleanComparisonOpTest__TestAllOnesUInt64 + { + private const int VectorSize = 16; + + private const int Op1ElementCount = VectorSize / sizeof(UInt64); + + private static UInt64[] _data = new UInt64[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private BooleanUnaryOpTest__DataTable _dataTable; + + static BooleanComparisonOpTest__TestAllOnesUInt64() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (ulong)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), VectorSize); + } + + public BooleanComparisonOpTest__TestAllOnesUInt64() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (ulong)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), VectorSize); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (ulong)(random.Next(0, int.MaxValue)); } + _dataTable = new BooleanUnaryOpTest__DataTable(_data, VectorSize); + } + + public bool IsSupported => Sse41.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse41.TestAllOnes( + Unsafe.Read>(_dataTable.inArrayPtr) + ); + + ValidateResult(_dataTable.inArrayPtr, result); + } + + public void RunBasicScenario_Load() + { + var result = Sse41.TestAllOnes( + Sse2.LoadVector128((UInt64*)(_dataTable.inArrayPtr)) + ); + + ValidateResult(_dataTable.inArrayPtr, result); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse41.TestAllOnes( + Sse2.LoadAlignedVector128((UInt64*)(_dataTable.inArrayPtr)) + ); + + ValidateResult(_dataTable.inArrayPtr, result); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestAllOnes), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr) + }); + + ValidateResult(_dataTable.inArrayPtr, (bool)(result)); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestAllOnes), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((UInt64*)(_dataTable.inArrayPtr)) + }); + + ValidateResult(_dataTable.inArrayPtr, (bool)(result)); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestAllOnes), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((UInt64*)(_dataTable.inArrayPtr)) + }); + + ValidateResult(_dataTable.inArrayPtr, (bool)(result)); + } + + public void RunClsVarScenario() + { + var result = Sse41.TestAllOnes( + _clsVar + ); + + ValidateResult(_clsVar, result); + } + + public void RunLclVarScenario_UnsafeRead() + { + var value = Unsafe.Read>(_dataTable.inArrayPtr); + var result = Sse41.TestAllOnes(value); + + ValidateResult(value, result); + } + + public void RunLclVarScenario_Load() + { + var value = Sse2.LoadVector128((UInt64*)(_dataTable.inArrayPtr)); + var result = Sse41.TestAllOnes(value); + + ValidateResult(value, result); + } + + public void RunLclVarScenario_LoadAligned() + { + var value = Sse2.LoadAlignedVector128((UInt64*)(_dataTable.inArrayPtr)); + var result = Sse41.TestAllOnes(value); + + ValidateResult(value, result); + } + + public void RunLclFldScenario() + { + var test = new BooleanComparisonOpTest__TestAllOnesUInt64(); + var result = Sse41.TestAllOnes(test._fld); + + ValidateResult(test._fld, result); + } + + public void RunFldScenario() + { + var result = Sse41.TestAllOnes(_fld); + + ValidateResult(_fld, result); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128 value, bool result, [CallerMemberName] string method = "") + { + UInt64[] inArray = new UInt64[Op1ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray[0]), value); + + ValidateResult(inArray, result, method); + } + + private void ValidateResult(void* value, bool result, [CallerMemberName] string method = "") + { + UInt64[] inArray = new UInt64[Op1ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(value), VectorSize); + + ValidateResult(inArray, result, method); + } + + private void ValidateResult(UInt64[] value, bool result, [CallerMemberName] string method = "") + { + var expectedResult = true; + + for (var i = 0; i < Op1ElementCount; i++) + { + expectedResult &= ((~value[i] & ulong.MaxValue) == 0); + } + + if (expectedResult != result) + { + Succeeded = false; + + Console.WriteLine($"{nameof(Sse41)}.{nameof(Sse41.TestAllOnes)}(Vector128): {method} failed:"); + Console.WriteLine($" value: ({string.Join(", ", value)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestAllZeros.Byte.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestAllZeros.Byte.cs new file mode 100644 index 000000000000..19751666bad7 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestAllZeros.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 TestAllZerosByte() + { + var test = new BooleanBinaryOpTest__TestAllZerosByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Sse2.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 (Sse2.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 (Sse2.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 BooleanBinaryOpTest__TestAllZerosByte + { + private const int VectorSize = 16; + + private const int Op1ElementCount = VectorSize / sizeof(Byte); + private const int Op2ElementCount = VectorSize / sizeof(Byte); + + private static Byte[] _data1 = new Byte[Op1ElementCount]; + private static Byte[] _data2 = new Byte[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private BooleanBinaryOpTest__DataTable _dataTable; + + static BooleanBinaryOpTest__TestAllZerosByte() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (byte)(random.Next(0, byte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (byte)(random.Next(0, byte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), VectorSize); + } + + public BooleanBinaryOpTest__TestAllZerosByte() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (byte)(random.Next(0, byte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (byte)(random.Next(0, byte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), VectorSize); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (byte)(random.Next(0, byte.MaxValue)); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (byte)(random.Next(0, byte.MaxValue)); } + _dataTable = new BooleanBinaryOpTest__DataTable(_data1, _data2, VectorSize); + } + + public bool IsSupported => Sse41.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse41.TestAllZeros( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunBasicScenario_Load() + { + var result = Sse41.TestAllZeros( + Sse2.LoadVector128((Byte*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Byte*)(_dataTable.inArray2Ptr)) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse41.TestAllZeros( + Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray2Ptr)) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestAllZeros), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestAllZeros), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Byte*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Byte*)(_dataTable.inArray2Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestAllZeros), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray2Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunClsVarScenario() + { + var result = Sse41.TestAllZeros( + _clsVar1, + _clsVar2 + ); + + ValidateResult(_clsVar1, _clsVar2, result); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read>(_dataTable.inArray1Ptr); + var right = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = Sse41.TestAllZeros(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((Byte*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((Byte*)(_dataTable.inArray2Ptr)); + var result = Sse41.TestAllZeros(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray2Ptr)); + var result = Sse41.TestAllZeros(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclFldScenario() + { + var test = new BooleanBinaryOpTest__TestAllZerosByte(); + var result = Sse41.TestAllZeros(test._fld1, test._fld2); + + ValidateResult(test._fld1, test._fld2, result); + } + + public void RunFldScenario() + { + var result = Sse41.TestAllZeros(_fld1, _fld2); + + ValidateResult(_fld1, _fld2, result); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128 left, Vector128 right, bool result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + Byte[] inArray2 = new Byte[Op2ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + + ValidateResult(inArray1, inArray2, result, method); + } + + private void ValidateResult(void* left, void* right, bool result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + Byte[] inArray2 = new Byte[Op2ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + + ValidateResult(inArray1, inArray2, result, method); + } + + private void ValidateResult(Byte[] left, Byte[] right, bool result, [CallerMemberName] string method = "") + { + var expectedResult = true; + + for (var i = 0; i < Op1ElementCount; i++) + { + expectedResult &= ((left[i] & right[i]) == 0); + } + + if (expectedResult != result) + { + Succeeded = false; + + Console.WriteLine($"{nameof(Sse41)}.{nameof(Sse41.TestAllZeros)}(Vector128, Vector128): {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/Sse41/TestAllZeros.Int16.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestAllZeros.Int16.cs new file mode 100644 index 000000000000..dc59464ba929 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestAllZeros.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 TestAllZerosInt16() + { + var test = new BooleanBinaryOpTest__TestAllZerosInt16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Sse2.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 (Sse2.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 (Sse2.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 BooleanBinaryOpTest__TestAllZerosInt16 + { + private const int VectorSize = 16; + + private const int Op1ElementCount = VectorSize / sizeof(Int16); + private const int Op2ElementCount = VectorSize / sizeof(Int16); + + private static Int16[] _data1 = new Int16[Op1ElementCount]; + private static Int16[] _data2 = new Int16[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private BooleanBinaryOpTest__DataTable _dataTable; + + static BooleanBinaryOpTest__TestAllZerosInt16() + { + 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, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (short)(random.Next(short.MinValue, short.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), VectorSize); + } + + public BooleanBinaryOpTest__TestAllZerosInt16() + { + 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, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (short)(random.Next(short.MinValue, short.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), VectorSize); + + 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 BooleanBinaryOpTest__DataTable(_data1, _data2, VectorSize); + } + + public bool IsSupported => Sse41.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse41.TestAllZeros( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunBasicScenario_Load() + { + var result = Sse41.TestAllZeros( + Sse2.LoadVector128((Int16*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Int16*)(_dataTable.inArray2Ptr)) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse41.TestAllZeros( + Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray2Ptr)) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestAllZeros), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestAllZeros), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Int16*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Int16*)(_dataTable.inArray2Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestAllZeros), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray2Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunClsVarScenario() + { + var result = Sse41.TestAllZeros( + _clsVar1, + _clsVar2 + ); + + ValidateResult(_clsVar1, _clsVar2, result); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read>(_dataTable.inArray1Ptr); + var right = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = Sse41.TestAllZeros(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((Int16*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((Int16*)(_dataTable.inArray2Ptr)); + var result = Sse41.TestAllZeros(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray2Ptr)); + var result = Sse41.TestAllZeros(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclFldScenario() + { + var test = new BooleanBinaryOpTest__TestAllZerosInt16(); + var result = Sse41.TestAllZeros(test._fld1, test._fld2); + + ValidateResult(test._fld1, test._fld2, result); + } + + public void RunFldScenario() + { + var result = Sse41.TestAllZeros(_fld1, _fld2); + + ValidateResult(_fld1, _fld2, result); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128 left, Vector128 right, bool result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + + ValidateResult(inArray1, inArray2, result, method); + } + + private void ValidateResult(void* left, void* right, bool result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + + ValidateResult(inArray1, inArray2, result, method); + } + + private void ValidateResult(Int16[] left, Int16[] right, bool result, [CallerMemberName] string method = "") + { + var expectedResult = true; + + for (var i = 0; i < Op1ElementCount; i++) + { + expectedResult &= ((left[i] & right[i]) == 0); + } + + if (expectedResult != result) + { + Succeeded = false; + + Console.WriteLine($"{nameof(Sse41)}.{nameof(Sse41.TestAllZeros)}(Vector128, Vector128): {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/Sse41/TestAllZeros.Int32.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestAllZeros.Int32.cs new file mode 100644 index 000000000000..230901ae5431 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestAllZeros.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 TestAllZerosInt32() + { + var test = new BooleanBinaryOpTest__TestAllZerosInt32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Sse2.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 (Sse2.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 (Sse2.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 BooleanBinaryOpTest__TestAllZerosInt32 + { + private const int VectorSize = 16; + + private const int Op1ElementCount = VectorSize / sizeof(Int32); + private const int Op2ElementCount = VectorSize / sizeof(Int32); + + private static Int32[] _data1 = new Int32[Op1ElementCount]; + private static Int32[] _data2 = new Int32[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private BooleanBinaryOpTest__DataTable _dataTable; + + static BooleanBinaryOpTest__TestAllZerosInt32() + { + 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, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (int)(random.Next(int.MinValue, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), VectorSize); + } + + public BooleanBinaryOpTest__TestAllZerosInt32() + { + 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, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (int)(random.Next(int.MinValue, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), VectorSize); + + 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 BooleanBinaryOpTest__DataTable(_data1, _data2, VectorSize); + } + + public bool IsSupported => Sse41.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse41.TestAllZeros( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunBasicScenario_Load() + { + var result = Sse41.TestAllZeros( + Sse2.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Int32*)(_dataTable.inArray2Ptr)) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse41.TestAllZeros( + Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray2Ptr)) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestAllZeros), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestAllZeros), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Int32*)(_dataTable.inArray2Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestAllZeros), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray2Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunClsVarScenario() + { + var result = Sse41.TestAllZeros( + _clsVar1, + _clsVar2 + ); + + ValidateResult(_clsVar1, _clsVar2, result); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read>(_dataTable.inArray1Ptr); + var right = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = Sse41.TestAllZeros(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((Int32*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((Int32*)(_dataTable.inArray2Ptr)); + var result = Sse41.TestAllZeros(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray2Ptr)); + var result = Sse41.TestAllZeros(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclFldScenario() + { + var test = new BooleanBinaryOpTest__TestAllZerosInt32(); + var result = Sse41.TestAllZeros(test._fld1, test._fld2); + + ValidateResult(test._fld1, test._fld2, result); + } + + public void RunFldScenario() + { + var result = Sse41.TestAllZeros(_fld1, _fld2); + + ValidateResult(_fld1, _fld2, result); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128 left, Vector128 right, bool result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + + ValidateResult(inArray1, inArray2, result, method); + } + + private void ValidateResult(void* left, void* right, bool result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + + ValidateResult(inArray1, inArray2, result, method); + } + + private void ValidateResult(Int32[] left, Int32[] right, bool result, [CallerMemberName] string method = "") + { + var expectedResult = true; + + for (var i = 0; i < Op1ElementCount; i++) + { + expectedResult &= ((left[i] & right[i]) == 0); + } + + if (expectedResult != result) + { + Succeeded = false; + + Console.WriteLine($"{nameof(Sse41)}.{nameof(Sse41.TestAllZeros)}(Vector128, Vector128): {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/Sse41/TestAllZeros.Int64.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestAllZeros.Int64.cs new file mode 100644 index 000000000000..e3925135e1f5 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestAllZeros.Int64.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 TestAllZerosInt64() + { + var test = new BooleanBinaryOpTest__TestAllZerosInt64(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Sse2.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 (Sse2.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 (Sse2.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 BooleanBinaryOpTest__TestAllZerosInt64 + { + private const int VectorSize = 16; + + private const int Op1ElementCount = VectorSize / sizeof(Int64); + private const int Op2ElementCount = VectorSize / sizeof(Int64); + + private static Int64[] _data1 = new Int64[Op1ElementCount]; + private static Int64[] _data2 = new Int64[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private BooleanBinaryOpTest__DataTable _dataTable; + + static BooleanBinaryOpTest__TestAllZerosInt64() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (long)(random.Next(int.MinValue, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (long)(random.Next(int.MinValue, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), VectorSize); + } + + public BooleanBinaryOpTest__TestAllZerosInt64() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (long)(random.Next(int.MinValue, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (long)(random.Next(int.MinValue, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), VectorSize); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (long)(random.Next(int.MinValue, int.MaxValue)); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (long)(random.Next(int.MinValue, int.MaxValue)); } + _dataTable = new BooleanBinaryOpTest__DataTable(_data1, _data2, VectorSize); + } + + public bool IsSupported => Sse41.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse41.TestAllZeros( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunBasicScenario_Load() + { + var result = Sse41.TestAllZeros( + Sse2.LoadVector128((Int64*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Int64*)(_dataTable.inArray2Ptr)) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse41.TestAllZeros( + Sse2.LoadAlignedVector128((Int64*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Int64*)(_dataTable.inArray2Ptr)) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestAllZeros), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestAllZeros), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Int64*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Int64*)(_dataTable.inArray2Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestAllZeros), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Int64*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Int64*)(_dataTable.inArray2Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunClsVarScenario() + { + var result = Sse41.TestAllZeros( + _clsVar1, + _clsVar2 + ); + + ValidateResult(_clsVar1, _clsVar2, result); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read>(_dataTable.inArray1Ptr); + var right = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = Sse41.TestAllZeros(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((Int64*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((Int64*)(_dataTable.inArray2Ptr)); + var result = Sse41.TestAllZeros(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((Int64*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((Int64*)(_dataTable.inArray2Ptr)); + var result = Sse41.TestAllZeros(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclFldScenario() + { + var test = new BooleanBinaryOpTest__TestAllZerosInt64(); + var result = Sse41.TestAllZeros(test._fld1, test._fld2); + + ValidateResult(test._fld1, test._fld2, result); + } + + public void RunFldScenario() + { + var result = Sse41.TestAllZeros(_fld1, _fld2); + + ValidateResult(_fld1, _fld2, result); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128 left, Vector128 right, bool result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + + ValidateResult(inArray1, inArray2, result, method); + } + + private void ValidateResult(void* left, void* right, bool result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + + ValidateResult(inArray1, inArray2, result, method); + } + + private void ValidateResult(Int64[] left, Int64[] right, bool result, [CallerMemberName] string method = "") + { + var expectedResult = true; + + for (var i = 0; i < Op1ElementCount; i++) + { + expectedResult &= ((left[i] & right[i]) == 0); + } + + if (expectedResult != result) + { + Succeeded = false; + + Console.WriteLine($"{nameof(Sse41)}.{nameof(Sse41.TestAllZeros)}(Vector128, Vector128): {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/Sse41/TestAllZeros.SByte.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestAllZeros.SByte.cs new file mode 100644 index 000000000000..37387aadadfd --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestAllZeros.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 TestAllZerosSByte() + { + var test = new BooleanBinaryOpTest__TestAllZerosSByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Sse2.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 (Sse2.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 (Sse2.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 BooleanBinaryOpTest__TestAllZerosSByte + { + private const int VectorSize = 16; + + private const int Op1ElementCount = VectorSize / sizeof(SByte); + private const int Op2ElementCount = VectorSize / sizeof(SByte); + + private static SByte[] _data1 = new SByte[Op1ElementCount]; + private static SByte[] _data2 = new SByte[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private BooleanBinaryOpTest__DataTable _dataTable; + + static BooleanBinaryOpTest__TestAllZerosSByte() + { + 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, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), VectorSize); + } + + public BooleanBinaryOpTest__TestAllZerosSByte() + { + 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, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), VectorSize); + + 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 BooleanBinaryOpTest__DataTable(_data1, _data2, VectorSize); + } + + public bool IsSupported => Sse41.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse41.TestAllZeros( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunBasicScenario_Load() + { + var result = Sse41.TestAllZeros( + Sse2.LoadVector128((SByte*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((SByte*)(_dataTable.inArray2Ptr)) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse41.TestAllZeros( + Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArray2Ptr)) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestAllZeros), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestAllZeros), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((SByte*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((SByte*)(_dataTable.inArray2Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestAllZeros), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArray2Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunClsVarScenario() + { + var result = Sse41.TestAllZeros( + _clsVar1, + _clsVar2 + ); + + ValidateResult(_clsVar1, _clsVar2, result); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read>(_dataTable.inArray1Ptr); + var right = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = Sse41.TestAllZeros(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((SByte*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((SByte*)(_dataTable.inArray2Ptr)); + var result = Sse41.TestAllZeros(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArray2Ptr)); + var result = Sse41.TestAllZeros(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclFldScenario() + { + var test = new BooleanBinaryOpTest__TestAllZerosSByte(); + var result = Sse41.TestAllZeros(test._fld1, test._fld2); + + ValidateResult(test._fld1, test._fld2, result); + } + + public void RunFldScenario() + { + var result = Sse41.TestAllZeros(_fld1, _fld2); + + ValidateResult(_fld1, _fld2, result); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128 left, Vector128 right, bool result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + + ValidateResult(inArray1, inArray2, result, method); + } + + private void ValidateResult(void* left, void* right, bool result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + + ValidateResult(inArray1, inArray2, result, method); + } + + private void ValidateResult(SByte[] left, SByte[] right, bool result, [CallerMemberName] string method = "") + { + var expectedResult = true; + + for (var i = 0; i < Op1ElementCount; i++) + { + expectedResult &= ((left[i] & right[i]) == 0); + } + + if (expectedResult != result) + { + Succeeded = false; + + Console.WriteLine($"{nameof(Sse41)}.{nameof(Sse41.TestAllZeros)}(Vector128, Vector128): {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/Sse41/TestAllZeros.UInt16.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestAllZeros.UInt16.cs new file mode 100644 index 000000000000..28f92b8c50f3 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestAllZeros.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 TestAllZerosUInt16() + { + var test = new BooleanBinaryOpTest__TestAllZerosUInt16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Sse2.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 (Sse2.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 (Sse2.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 BooleanBinaryOpTest__TestAllZerosUInt16 + { + private const int VectorSize = 16; + + private const int Op1ElementCount = VectorSize / sizeof(UInt16); + private const int Op2ElementCount = VectorSize / sizeof(UInt16); + + private static UInt16[] _data1 = new UInt16[Op1ElementCount]; + private static UInt16[] _data2 = new UInt16[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private BooleanBinaryOpTest__DataTable _dataTable; + + static BooleanBinaryOpTest__TestAllZerosUInt16() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (ushort)(random.Next(0, ushort.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (ushort)(random.Next(0, ushort.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), VectorSize); + } + + public BooleanBinaryOpTest__TestAllZerosUInt16() + { + 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, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (ushort)(random.Next(0, ushort.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), VectorSize); + + 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 BooleanBinaryOpTest__DataTable(_data1, _data2, VectorSize); + } + + public bool IsSupported => Sse41.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse41.TestAllZeros( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunBasicScenario_Load() + { + var result = Sse41.TestAllZeros( + Sse2.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse41.TestAllZeros( + Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArray2Ptr)) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestAllZeros), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestAllZeros), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestAllZeros), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArray2Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunClsVarScenario() + { + var result = Sse41.TestAllZeros( + _clsVar1, + _clsVar2 + ); + + ValidateResult(_clsVar1, _clsVar2, result); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read>(_dataTable.inArray1Ptr); + var right = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = Sse41.TestAllZeros(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)); + var result = Sse41.TestAllZeros(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArray2Ptr)); + var result = Sse41.TestAllZeros(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclFldScenario() + { + var test = new BooleanBinaryOpTest__TestAllZerosUInt16(); + var result = Sse41.TestAllZeros(test._fld1, test._fld2); + + ValidateResult(test._fld1, test._fld2, result); + } + + public void RunFldScenario() + { + var result = Sse41.TestAllZeros(_fld1, _fld2); + + ValidateResult(_fld1, _fld2, result); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128 left, Vector128 right, bool result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + + ValidateResult(inArray1, inArray2, result, method); + } + + private void ValidateResult(void* left, void* right, bool result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + + ValidateResult(inArray1, inArray2, result, method); + } + + private void ValidateResult(UInt16[] left, UInt16[] right, bool result, [CallerMemberName] string method = "") + { + var expectedResult = true; + + for (var i = 0; i < Op1ElementCount; i++) + { + expectedResult &= ((left[i] & right[i]) == 0); + } + + if (expectedResult != result) + { + Succeeded = false; + + Console.WriteLine($"{nameof(Sse41)}.{nameof(Sse41.TestAllZeros)}(Vector128, Vector128): {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/Sse41/TestAllZeros.UInt32.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestAllZeros.UInt32.cs new file mode 100644 index 000000000000..bc7e223fb149 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestAllZeros.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 TestAllZerosUInt32() + { + var test = new BooleanBinaryOpTest__TestAllZerosUInt32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Sse2.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 (Sse2.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 (Sse2.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 BooleanBinaryOpTest__TestAllZerosUInt32 + { + private const int VectorSize = 16; + + private const int Op1ElementCount = VectorSize / sizeof(UInt32); + private const int Op2ElementCount = VectorSize / sizeof(UInt32); + + private static UInt32[] _data1 = new UInt32[Op1ElementCount]; + private static UInt32[] _data2 = new UInt32[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private BooleanBinaryOpTest__DataTable _dataTable; + + static BooleanBinaryOpTest__TestAllZerosUInt32() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (uint)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (uint)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), VectorSize); + } + + public BooleanBinaryOpTest__TestAllZerosUInt32() + { + 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, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (uint)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(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 BooleanBinaryOpTest__DataTable(_data1, _data2, VectorSize); + } + + public bool IsSupported => Sse41.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse41.TestAllZeros( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunBasicScenario_Load() + { + var result = Sse41.TestAllZeros( + Sse2.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse41.TestAllZeros( + Sse2.LoadAlignedVector128((UInt32*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((UInt32*)(_dataTable.inArray2Ptr)) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestAllZeros), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestAllZeros), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestAllZeros), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((UInt32*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((UInt32*)(_dataTable.inArray2Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunClsVarScenario() + { + var result = Sse41.TestAllZeros( + _clsVar1, + _clsVar2 + ); + + ValidateResult(_clsVar1, _clsVar2, result); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read>(_dataTable.inArray1Ptr); + var right = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = Sse41.TestAllZeros(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)); + var result = Sse41.TestAllZeros(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((UInt32*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((UInt32*)(_dataTable.inArray2Ptr)); + var result = Sse41.TestAllZeros(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclFldScenario() + { + var test = new BooleanBinaryOpTest__TestAllZerosUInt32(); + var result = Sse41.TestAllZeros(test._fld1, test._fld2); + + ValidateResult(test._fld1, test._fld2, result); + } + + public void RunFldScenario() + { + var result = Sse41.TestAllZeros(_fld1, _fld2); + + ValidateResult(_fld1, _fld2, result); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128 left, Vector128 right, bool result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + + ValidateResult(inArray1, inArray2, result, method); + } + + private void ValidateResult(void* left, void* right, bool result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + + ValidateResult(inArray1, inArray2, result, method); + } + + private void ValidateResult(UInt32[] left, UInt32[] right, bool result, [CallerMemberName] string method = "") + { + var expectedResult = true; + + for (var i = 0; i < Op1ElementCount; i++) + { + expectedResult &= ((left[i] & right[i]) == 0); + } + + if (expectedResult != result) + { + Succeeded = false; + + Console.WriteLine($"{nameof(Sse41)}.{nameof(Sse41.TestAllZeros)}(Vector128, Vector128): {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/Sse41/TestAllZeros.UInt64.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestAllZeros.UInt64.cs new file mode 100644 index 000000000000..03b3a2ac3bf3 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestAllZeros.UInt64.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 TestAllZerosUInt64() + { + var test = new BooleanBinaryOpTest__TestAllZerosUInt64(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Sse2.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 (Sse2.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 (Sse2.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 BooleanBinaryOpTest__TestAllZerosUInt64 + { + private const int VectorSize = 16; + + private const int Op1ElementCount = VectorSize / sizeof(UInt64); + private const int Op2ElementCount = VectorSize / sizeof(UInt64); + + private static UInt64[] _data1 = new UInt64[Op1ElementCount]; + private static UInt64[] _data2 = new UInt64[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private BooleanBinaryOpTest__DataTable _dataTable; + + static BooleanBinaryOpTest__TestAllZerosUInt64() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (ulong)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (ulong)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), VectorSize); + } + + public BooleanBinaryOpTest__TestAllZerosUInt64() + { + 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, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (ulong)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(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 BooleanBinaryOpTest__DataTable(_data1, _data2, VectorSize); + } + + public bool IsSupported => Sse41.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse41.TestAllZeros( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunBasicScenario_Load() + { + var result = Sse41.TestAllZeros( + Sse2.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((UInt64*)(_dataTable.inArray2Ptr)) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse41.TestAllZeros( + Sse2.LoadAlignedVector128((UInt64*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((UInt64*)(_dataTable.inArray2Ptr)) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestAllZeros), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestAllZeros), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((UInt64*)(_dataTable.inArray2Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestAllZeros), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((UInt64*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((UInt64*)(_dataTable.inArray2Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunClsVarScenario() + { + var result = Sse41.TestAllZeros( + _clsVar1, + _clsVar2 + ); + + ValidateResult(_clsVar1, _clsVar2, result); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read>(_dataTable.inArray1Ptr); + var right = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = Sse41.TestAllZeros(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((UInt64*)(_dataTable.inArray2Ptr)); + var result = Sse41.TestAllZeros(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((UInt64*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((UInt64*)(_dataTable.inArray2Ptr)); + var result = Sse41.TestAllZeros(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclFldScenario() + { + var test = new BooleanBinaryOpTest__TestAllZerosUInt64(); + var result = Sse41.TestAllZeros(test._fld1, test._fld2); + + ValidateResult(test._fld1, test._fld2, result); + } + + public void RunFldScenario() + { + var result = Sse41.TestAllZeros(_fld1, _fld2); + + ValidateResult(_fld1, _fld2, result); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128 left, Vector128 right, bool result, [CallerMemberName] string method = "") + { + UInt64[] inArray1 = new UInt64[Op1ElementCount]; + UInt64[] inArray2 = new UInt64[Op2ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + + ValidateResult(inArray1, inArray2, result, method); + } + + private void ValidateResult(void* left, void* right, bool result, [CallerMemberName] string method = "") + { + UInt64[] inArray1 = new UInt64[Op1ElementCount]; + UInt64[] inArray2 = new UInt64[Op2ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + + ValidateResult(inArray1, inArray2, result, method); + } + + private void ValidateResult(UInt64[] left, UInt64[] right, bool result, [CallerMemberName] string method = "") + { + var expectedResult = true; + + for (var i = 0; i < Op1ElementCount; i++) + { + expectedResult &= ((left[i] & right[i]) == 0); + } + + if (expectedResult != result) + { + Succeeded = false; + + Console.WriteLine($"{nameof(Sse41)}.{nameof(Sse41.TestAllZeros)}(Vector128, Vector128): {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/Sse41/TestC.Byte.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestC.Byte.cs new file mode 100644 index 000000000000..52e200166faa --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestC.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 TestCByte() + { + var test = new BooleanBinaryOpTest__TestCByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Sse2.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 (Sse2.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 (Sse2.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 BooleanBinaryOpTest__TestCByte + { + private const int VectorSize = 16; + + private const int Op1ElementCount = VectorSize / sizeof(Byte); + private const int Op2ElementCount = VectorSize / sizeof(Byte); + + private static Byte[] _data1 = new Byte[Op1ElementCount]; + private static Byte[] _data2 = new Byte[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private BooleanBinaryOpTest__DataTable _dataTable; + + static BooleanBinaryOpTest__TestCByte() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (byte)(random.Next(0, byte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (byte)(random.Next(0, byte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), VectorSize); + } + + public BooleanBinaryOpTest__TestCByte() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (byte)(random.Next(0, byte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (byte)(random.Next(0, byte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), VectorSize); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (byte)(random.Next(0, byte.MaxValue)); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (byte)(random.Next(0, byte.MaxValue)); } + _dataTable = new BooleanBinaryOpTest__DataTable(_data1, _data2, VectorSize); + } + + public bool IsSupported => Sse41.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse41.TestC( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunBasicScenario_Load() + { + var result = Sse41.TestC( + Sse2.LoadVector128((Byte*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Byte*)(_dataTable.inArray2Ptr)) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse41.TestC( + Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray2Ptr)) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestC), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestC), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Byte*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Byte*)(_dataTable.inArray2Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestC), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray2Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunClsVarScenario() + { + var result = Sse41.TestC( + _clsVar1, + _clsVar2 + ); + + ValidateResult(_clsVar1, _clsVar2, result); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read>(_dataTable.inArray1Ptr); + var right = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = Sse41.TestC(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((Byte*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((Byte*)(_dataTable.inArray2Ptr)); + var result = Sse41.TestC(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray2Ptr)); + var result = Sse41.TestC(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclFldScenario() + { + var test = new BooleanBinaryOpTest__TestCByte(); + var result = Sse41.TestC(test._fld1, test._fld2); + + ValidateResult(test._fld1, test._fld2, result); + } + + public void RunFldScenario() + { + var result = Sse41.TestC(_fld1, _fld2); + + ValidateResult(_fld1, _fld2, result); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128 left, Vector128 right, bool result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + Byte[] inArray2 = new Byte[Op2ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + + ValidateResult(inArray1, inArray2, result, method); + } + + private void ValidateResult(void* left, void* right, bool result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + Byte[] inArray2 = new Byte[Op2ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + + ValidateResult(inArray1, inArray2, result, method); + } + + private void ValidateResult(Byte[] left, Byte[] right, bool result, [CallerMemberName] string method = "") + { + var expectedResult = true; + + for (var i = 0; i < Op1ElementCount; i++) + { + expectedResult &= ((~left[i] & right[i]) == 0); + } + + if (expectedResult != result) + { + Succeeded = false; + + Console.WriteLine($"{nameof(Sse41)}.{nameof(Sse41.TestC)}(Vector128, Vector128): {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/Sse41/TestC.Int16.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestC.Int16.cs new file mode 100644 index 000000000000..be483c157d94 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestC.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 TestCInt16() + { + var test = new BooleanBinaryOpTest__TestCInt16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Sse2.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 (Sse2.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 (Sse2.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 BooleanBinaryOpTest__TestCInt16 + { + private const int VectorSize = 16; + + private const int Op1ElementCount = VectorSize / sizeof(Int16); + private const int Op2ElementCount = VectorSize / sizeof(Int16); + + private static Int16[] _data1 = new Int16[Op1ElementCount]; + private static Int16[] _data2 = new Int16[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private BooleanBinaryOpTest__DataTable _dataTable; + + static BooleanBinaryOpTest__TestCInt16() + { + 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, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (short)(random.Next(short.MinValue, short.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), VectorSize); + } + + public BooleanBinaryOpTest__TestCInt16() + { + 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, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (short)(random.Next(short.MinValue, short.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), VectorSize); + + 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 BooleanBinaryOpTest__DataTable(_data1, _data2, VectorSize); + } + + public bool IsSupported => Sse41.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse41.TestC( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunBasicScenario_Load() + { + var result = Sse41.TestC( + Sse2.LoadVector128((Int16*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Int16*)(_dataTable.inArray2Ptr)) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse41.TestC( + Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray2Ptr)) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestC), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestC), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Int16*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Int16*)(_dataTable.inArray2Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestC), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray2Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunClsVarScenario() + { + var result = Sse41.TestC( + _clsVar1, + _clsVar2 + ); + + ValidateResult(_clsVar1, _clsVar2, result); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read>(_dataTable.inArray1Ptr); + var right = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = Sse41.TestC(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((Int16*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((Int16*)(_dataTable.inArray2Ptr)); + var result = Sse41.TestC(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray2Ptr)); + var result = Sse41.TestC(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclFldScenario() + { + var test = new BooleanBinaryOpTest__TestCInt16(); + var result = Sse41.TestC(test._fld1, test._fld2); + + ValidateResult(test._fld1, test._fld2, result); + } + + public void RunFldScenario() + { + var result = Sse41.TestC(_fld1, _fld2); + + ValidateResult(_fld1, _fld2, result); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128 left, Vector128 right, bool result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + + ValidateResult(inArray1, inArray2, result, method); + } + + private void ValidateResult(void* left, void* right, bool result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + + ValidateResult(inArray1, inArray2, result, method); + } + + private void ValidateResult(Int16[] left, Int16[] right, bool result, [CallerMemberName] string method = "") + { + var expectedResult = true; + + for (var i = 0; i < Op1ElementCount; i++) + { + expectedResult &= ((~left[i] & right[i]) == 0); + } + + if (expectedResult != result) + { + Succeeded = false; + + Console.WriteLine($"{nameof(Sse41)}.{nameof(Sse41.TestC)}(Vector128, Vector128): {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/Sse41/TestC.Int32.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestC.Int32.cs new file mode 100644 index 000000000000..b6e6004b3714 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestC.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 TestCInt32() + { + var test = new BooleanBinaryOpTest__TestCInt32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Sse2.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 (Sse2.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 (Sse2.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 BooleanBinaryOpTest__TestCInt32 + { + private const int VectorSize = 16; + + private const int Op1ElementCount = VectorSize / sizeof(Int32); + private const int Op2ElementCount = VectorSize / sizeof(Int32); + + private static Int32[] _data1 = new Int32[Op1ElementCount]; + private static Int32[] _data2 = new Int32[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private BooleanBinaryOpTest__DataTable _dataTable; + + static BooleanBinaryOpTest__TestCInt32() + { + 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, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (int)(random.Next(int.MinValue, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), VectorSize); + } + + public BooleanBinaryOpTest__TestCInt32() + { + 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, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (int)(random.Next(int.MinValue, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), VectorSize); + + 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 BooleanBinaryOpTest__DataTable(_data1, _data2, VectorSize); + } + + public bool IsSupported => Sse41.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse41.TestC( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunBasicScenario_Load() + { + var result = Sse41.TestC( + Sse2.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Int32*)(_dataTable.inArray2Ptr)) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse41.TestC( + Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray2Ptr)) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestC), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestC), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Int32*)(_dataTable.inArray2Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestC), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray2Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunClsVarScenario() + { + var result = Sse41.TestC( + _clsVar1, + _clsVar2 + ); + + ValidateResult(_clsVar1, _clsVar2, result); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read>(_dataTable.inArray1Ptr); + var right = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = Sse41.TestC(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((Int32*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((Int32*)(_dataTable.inArray2Ptr)); + var result = Sse41.TestC(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray2Ptr)); + var result = Sse41.TestC(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclFldScenario() + { + var test = new BooleanBinaryOpTest__TestCInt32(); + var result = Sse41.TestC(test._fld1, test._fld2); + + ValidateResult(test._fld1, test._fld2, result); + } + + public void RunFldScenario() + { + var result = Sse41.TestC(_fld1, _fld2); + + ValidateResult(_fld1, _fld2, result); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128 left, Vector128 right, bool result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + + ValidateResult(inArray1, inArray2, result, method); + } + + private void ValidateResult(void* left, void* right, bool result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + + ValidateResult(inArray1, inArray2, result, method); + } + + private void ValidateResult(Int32[] left, Int32[] right, bool result, [CallerMemberName] string method = "") + { + var expectedResult = true; + + for (var i = 0; i < Op1ElementCount; i++) + { + expectedResult &= ((~left[i] & right[i]) == 0); + } + + if (expectedResult != result) + { + Succeeded = false; + + Console.WriteLine($"{nameof(Sse41)}.{nameof(Sse41.TestC)}(Vector128, Vector128): {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/Sse41/TestC.Int64.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestC.Int64.cs new file mode 100644 index 000000000000..55e126104d2d --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestC.Int64.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 TestCInt64() + { + var test = new BooleanBinaryOpTest__TestCInt64(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Sse2.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 (Sse2.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 (Sse2.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 BooleanBinaryOpTest__TestCInt64 + { + private const int VectorSize = 16; + + private const int Op1ElementCount = VectorSize / sizeof(Int64); + private const int Op2ElementCount = VectorSize / sizeof(Int64); + + private static Int64[] _data1 = new Int64[Op1ElementCount]; + private static Int64[] _data2 = new Int64[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private BooleanBinaryOpTest__DataTable _dataTable; + + static BooleanBinaryOpTest__TestCInt64() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (long)(random.Next(int.MinValue, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (long)(random.Next(int.MinValue, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), VectorSize); + } + + public BooleanBinaryOpTest__TestCInt64() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (long)(random.Next(int.MinValue, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (long)(random.Next(int.MinValue, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), VectorSize); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (long)(random.Next(int.MinValue, int.MaxValue)); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (long)(random.Next(int.MinValue, int.MaxValue)); } + _dataTable = new BooleanBinaryOpTest__DataTable(_data1, _data2, VectorSize); + } + + public bool IsSupported => Sse41.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse41.TestC( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunBasicScenario_Load() + { + var result = Sse41.TestC( + Sse2.LoadVector128((Int64*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Int64*)(_dataTable.inArray2Ptr)) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse41.TestC( + Sse2.LoadAlignedVector128((Int64*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Int64*)(_dataTable.inArray2Ptr)) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestC), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestC), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Int64*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Int64*)(_dataTable.inArray2Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestC), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Int64*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Int64*)(_dataTable.inArray2Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunClsVarScenario() + { + var result = Sse41.TestC( + _clsVar1, + _clsVar2 + ); + + ValidateResult(_clsVar1, _clsVar2, result); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read>(_dataTable.inArray1Ptr); + var right = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = Sse41.TestC(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((Int64*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((Int64*)(_dataTable.inArray2Ptr)); + var result = Sse41.TestC(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((Int64*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((Int64*)(_dataTable.inArray2Ptr)); + var result = Sse41.TestC(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclFldScenario() + { + var test = new BooleanBinaryOpTest__TestCInt64(); + var result = Sse41.TestC(test._fld1, test._fld2); + + ValidateResult(test._fld1, test._fld2, result); + } + + public void RunFldScenario() + { + var result = Sse41.TestC(_fld1, _fld2); + + ValidateResult(_fld1, _fld2, result); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128 left, Vector128 right, bool result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + + ValidateResult(inArray1, inArray2, result, method); + } + + private void ValidateResult(void* left, void* right, bool result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + + ValidateResult(inArray1, inArray2, result, method); + } + + private void ValidateResult(Int64[] left, Int64[] right, bool result, [CallerMemberName] string method = "") + { + var expectedResult = true; + + for (var i = 0; i < Op1ElementCount; i++) + { + expectedResult &= ((~left[i] & right[i]) == 0); + } + + if (expectedResult != result) + { + Succeeded = false; + + Console.WriteLine($"{nameof(Sse41)}.{nameof(Sse41.TestC)}(Vector128, Vector128): {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/Sse41/TestC.SByte.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestC.SByte.cs new file mode 100644 index 000000000000..474bc525d6c5 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestC.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 TestCSByte() + { + var test = new BooleanBinaryOpTest__TestCSByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Sse2.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 (Sse2.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 (Sse2.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 BooleanBinaryOpTest__TestCSByte + { + private const int VectorSize = 16; + + private const int Op1ElementCount = VectorSize / sizeof(SByte); + private const int Op2ElementCount = VectorSize / sizeof(SByte); + + private static SByte[] _data1 = new SByte[Op1ElementCount]; + private static SByte[] _data2 = new SByte[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private BooleanBinaryOpTest__DataTable _dataTable; + + static BooleanBinaryOpTest__TestCSByte() + { + 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, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), VectorSize); + } + + public BooleanBinaryOpTest__TestCSByte() + { + 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, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), VectorSize); + + 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 BooleanBinaryOpTest__DataTable(_data1, _data2, VectorSize); + } + + public bool IsSupported => Sse41.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse41.TestC( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunBasicScenario_Load() + { + var result = Sse41.TestC( + Sse2.LoadVector128((SByte*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((SByte*)(_dataTable.inArray2Ptr)) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse41.TestC( + Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArray2Ptr)) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestC), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestC), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((SByte*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((SByte*)(_dataTable.inArray2Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestC), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArray2Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunClsVarScenario() + { + var result = Sse41.TestC( + _clsVar1, + _clsVar2 + ); + + ValidateResult(_clsVar1, _clsVar2, result); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read>(_dataTable.inArray1Ptr); + var right = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = Sse41.TestC(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((SByte*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((SByte*)(_dataTable.inArray2Ptr)); + var result = Sse41.TestC(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArray2Ptr)); + var result = Sse41.TestC(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclFldScenario() + { + var test = new BooleanBinaryOpTest__TestCSByte(); + var result = Sse41.TestC(test._fld1, test._fld2); + + ValidateResult(test._fld1, test._fld2, result); + } + + public void RunFldScenario() + { + var result = Sse41.TestC(_fld1, _fld2); + + ValidateResult(_fld1, _fld2, result); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128 left, Vector128 right, bool result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + + ValidateResult(inArray1, inArray2, result, method); + } + + private void ValidateResult(void* left, void* right, bool result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + + ValidateResult(inArray1, inArray2, result, method); + } + + private void ValidateResult(SByte[] left, SByte[] right, bool result, [CallerMemberName] string method = "") + { + var expectedResult = true; + + for (var i = 0; i < Op1ElementCount; i++) + { + expectedResult &= ((~left[i] & right[i]) == 0); + } + + if (expectedResult != result) + { + Succeeded = false; + + Console.WriteLine($"{nameof(Sse41)}.{nameof(Sse41.TestC)}(Vector128, Vector128): {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/Sse41/TestC.UInt16.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestC.UInt16.cs new file mode 100644 index 000000000000..6f75a47a0b8d --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestC.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 TestCUInt16() + { + var test = new BooleanBinaryOpTest__TestCUInt16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Sse2.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 (Sse2.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 (Sse2.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 BooleanBinaryOpTest__TestCUInt16 + { + private const int VectorSize = 16; + + private const int Op1ElementCount = VectorSize / sizeof(UInt16); + private const int Op2ElementCount = VectorSize / sizeof(UInt16); + + private static UInt16[] _data1 = new UInt16[Op1ElementCount]; + private static UInt16[] _data2 = new UInt16[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private BooleanBinaryOpTest__DataTable _dataTable; + + static BooleanBinaryOpTest__TestCUInt16() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (ushort)(random.Next(0, ushort.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (ushort)(random.Next(0, ushort.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), VectorSize); + } + + public BooleanBinaryOpTest__TestCUInt16() + { + 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, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (ushort)(random.Next(0, ushort.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), VectorSize); + + 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 BooleanBinaryOpTest__DataTable(_data1, _data2, VectorSize); + } + + public bool IsSupported => Sse41.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse41.TestC( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunBasicScenario_Load() + { + var result = Sse41.TestC( + Sse2.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse41.TestC( + Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArray2Ptr)) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestC), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestC), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestC), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArray2Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunClsVarScenario() + { + var result = Sse41.TestC( + _clsVar1, + _clsVar2 + ); + + ValidateResult(_clsVar1, _clsVar2, result); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read>(_dataTable.inArray1Ptr); + var right = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = Sse41.TestC(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)); + var result = Sse41.TestC(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArray2Ptr)); + var result = Sse41.TestC(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclFldScenario() + { + var test = new BooleanBinaryOpTest__TestCUInt16(); + var result = Sse41.TestC(test._fld1, test._fld2); + + ValidateResult(test._fld1, test._fld2, result); + } + + public void RunFldScenario() + { + var result = Sse41.TestC(_fld1, _fld2); + + ValidateResult(_fld1, _fld2, result); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128 left, Vector128 right, bool result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + + ValidateResult(inArray1, inArray2, result, method); + } + + private void ValidateResult(void* left, void* right, bool result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + + ValidateResult(inArray1, inArray2, result, method); + } + + private void ValidateResult(UInt16[] left, UInt16[] right, bool result, [CallerMemberName] string method = "") + { + var expectedResult = true; + + for (var i = 0; i < Op1ElementCount; i++) + { + expectedResult &= ((~left[i] & right[i]) == 0); + } + + if (expectedResult != result) + { + Succeeded = false; + + Console.WriteLine($"{nameof(Sse41)}.{nameof(Sse41.TestC)}(Vector128, Vector128): {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/Sse41/TestC.UInt32.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestC.UInt32.cs new file mode 100644 index 000000000000..5c7b28995c76 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestC.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 TestCUInt32() + { + var test = new BooleanBinaryOpTest__TestCUInt32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Sse2.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 (Sse2.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 (Sse2.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 BooleanBinaryOpTest__TestCUInt32 + { + private const int VectorSize = 16; + + private const int Op1ElementCount = VectorSize / sizeof(UInt32); + private const int Op2ElementCount = VectorSize / sizeof(UInt32); + + private static UInt32[] _data1 = new UInt32[Op1ElementCount]; + private static UInt32[] _data2 = new UInt32[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private BooleanBinaryOpTest__DataTable _dataTable; + + static BooleanBinaryOpTest__TestCUInt32() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (uint)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (uint)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), VectorSize); + } + + public BooleanBinaryOpTest__TestCUInt32() + { + 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, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (uint)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(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 BooleanBinaryOpTest__DataTable(_data1, _data2, VectorSize); + } + + public bool IsSupported => Sse41.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse41.TestC( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunBasicScenario_Load() + { + var result = Sse41.TestC( + Sse2.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse41.TestC( + Sse2.LoadAlignedVector128((UInt32*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((UInt32*)(_dataTable.inArray2Ptr)) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestC), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestC), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestC), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((UInt32*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((UInt32*)(_dataTable.inArray2Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunClsVarScenario() + { + var result = Sse41.TestC( + _clsVar1, + _clsVar2 + ); + + ValidateResult(_clsVar1, _clsVar2, result); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read>(_dataTable.inArray1Ptr); + var right = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = Sse41.TestC(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)); + var result = Sse41.TestC(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((UInt32*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((UInt32*)(_dataTable.inArray2Ptr)); + var result = Sse41.TestC(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclFldScenario() + { + var test = new BooleanBinaryOpTest__TestCUInt32(); + var result = Sse41.TestC(test._fld1, test._fld2); + + ValidateResult(test._fld1, test._fld2, result); + } + + public void RunFldScenario() + { + var result = Sse41.TestC(_fld1, _fld2); + + ValidateResult(_fld1, _fld2, result); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128 left, Vector128 right, bool result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + + ValidateResult(inArray1, inArray2, result, method); + } + + private void ValidateResult(void* left, void* right, bool result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + + ValidateResult(inArray1, inArray2, result, method); + } + + private void ValidateResult(UInt32[] left, UInt32[] right, bool result, [CallerMemberName] string method = "") + { + var expectedResult = true; + + for (var i = 0; i < Op1ElementCount; i++) + { + expectedResult &= ((~left[i] & right[i]) == 0); + } + + if (expectedResult != result) + { + Succeeded = false; + + Console.WriteLine($"{nameof(Sse41)}.{nameof(Sse41.TestC)}(Vector128, Vector128): {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/Sse41/TestC.UInt64.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestC.UInt64.cs new file mode 100644 index 000000000000..85a5b3825eaa --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestC.UInt64.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 TestCUInt64() + { + var test = new BooleanBinaryOpTest__TestCUInt64(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Sse2.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 (Sse2.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 (Sse2.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 BooleanBinaryOpTest__TestCUInt64 + { + private const int VectorSize = 16; + + private const int Op1ElementCount = VectorSize / sizeof(UInt64); + private const int Op2ElementCount = VectorSize / sizeof(UInt64); + + private static UInt64[] _data1 = new UInt64[Op1ElementCount]; + private static UInt64[] _data2 = new UInt64[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private BooleanBinaryOpTest__DataTable _dataTable; + + static BooleanBinaryOpTest__TestCUInt64() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (ulong)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (ulong)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), VectorSize); + } + + public BooleanBinaryOpTest__TestCUInt64() + { + 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, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (ulong)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(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 BooleanBinaryOpTest__DataTable(_data1, _data2, VectorSize); + } + + public bool IsSupported => Sse41.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse41.TestC( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunBasicScenario_Load() + { + var result = Sse41.TestC( + Sse2.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((UInt64*)(_dataTable.inArray2Ptr)) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse41.TestC( + Sse2.LoadAlignedVector128((UInt64*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((UInt64*)(_dataTable.inArray2Ptr)) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestC), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestC), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((UInt64*)(_dataTable.inArray2Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestC), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((UInt64*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((UInt64*)(_dataTable.inArray2Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunClsVarScenario() + { + var result = Sse41.TestC( + _clsVar1, + _clsVar2 + ); + + ValidateResult(_clsVar1, _clsVar2, result); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read>(_dataTable.inArray1Ptr); + var right = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = Sse41.TestC(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((UInt64*)(_dataTable.inArray2Ptr)); + var result = Sse41.TestC(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((UInt64*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((UInt64*)(_dataTable.inArray2Ptr)); + var result = Sse41.TestC(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclFldScenario() + { + var test = new BooleanBinaryOpTest__TestCUInt64(); + var result = Sse41.TestC(test._fld1, test._fld2); + + ValidateResult(test._fld1, test._fld2, result); + } + + public void RunFldScenario() + { + var result = Sse41.TestC(_fld1, _fld2); + + ValidateResult(_fld1, _fld2, result); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128 left, Vector128 right, bool result, [CallerMemberName] string method = "") + { + UInt64[] inArray1 = new UInt64[Op1ElementCount]; + UInt64[] inArray2 = new UInt64[Op2ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + + ValidateResult(inArray1, inArray2, result, method); + } + + private void ValidateResult(void* left, void* right, bool result, [CallerMemberName] string method = "") + { + UInt64[] inArray1 = new UInt64[Op1ElementCount]; + UInt64[] inArray2 = new UInt64[Op2ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + + ValidateResult(inArray1, inArray2, result, method); + } + + private void ValidateResult(UInt64[] left, UInt64[] right, bool result, [CallerMemberName] string method = "") + { + var expectedResult = true; + + for (var i = 0; i < Op1ElementCount; i++) + { + expectedResult &= ((~left[i] & right[i]) == 0); + } + + if (expectedResult != result) + { + Succeeded = false; + + Console.WriteLine($"{nameof(Sse41)}.{nameof(Sse41.TestC)}(Vector128, Vector128): {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/Sse41/TestMixOnesZeros.Byte.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestMixOnesZeros.Byte.cs new file mode 100644 index 000000000000..d08d0c1fb52d --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestMixOnesZeros.Byte.cs @@ -0,0 +1,313 @@ +// 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 TestMixOnesZerosByte() + { + var test = new BooleanTwoComparisonOpTest__TestMixOnesZerosByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Sse2.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 (Sse2.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 (Sse2.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 BooleanTwoComparisonOpTest__TestMixOnesZerosByte + { + private const int VectorSize = 16; + + private const int Op1ElementCount = VectorSize / sizeof(Byte); + private const int Op2ElementCount = VectorSize / sizeof(Byte); + + private static Byte[] _data1 = new Byte[Op1ElementCount]; + private static Byte[] _data2 = new Byte[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private BooleanTwoComparisonOpTest__DataTable _dataTable; + + static BooleanTwoComparisonOpTest__TestMixOnesZerosByte() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (byte)(random.Next(0, byte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (byte)(random.Next(0, byte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), VectorSize); + } + + public BooleanTwoComparisonOpTest__TestMixOnesZerosByte() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (byte)(random.Next(0, byte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (byte)(random.Next(0, byte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), VectorSize); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (byte)(random.Next(0, byte.MaxValue)); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (byte)(random.Next(0, byte.MaxValue)); } + _dataTable = new BooleanTwoComparisonOpTest__DataTable(_data1, _data2, VectorSize); + } + + public bool IsSupported => Sse41.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse41.TestMixOnesZeros( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunBasicScenario_Load() + { + var result = Sse41.TestMixOnesZeros( + Sse2.LoadVector128((Byte*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Byte*)(_dataTable.inArray2Ptr)) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse41.TestMixOnesZeros( + Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray2Ptr)) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestMixOnesZeros), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestMixOnesZeros), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Byte*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Byte*)(_dataTable.inArray2Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestMixOnesZeros), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray2Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunClsVarScenario() + { + var result = Sse41.TestMixOnesZeros( + _clsVar1, + _clsVar2 + ); + + ValidateResult(_clsVar1, _clsVar2, result); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read>(_dataTable.inArray1Ptr); + var right = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = Sse41.TestMixOnesZeros(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((Byte*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((Byte*)(_dataTable.inArray2Ptr)); + var result = Sse41.TestMixOnesZeros(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray2Ptr)); + var result = Sse41.TestMixOnesZeros(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclFldScenario() + { + var test = new BooleanTwoComparisonOpTest__TestMixOnesZerosByte(); + var result = Sse41.TestMixOnesZeros(test._fld1, test._fld2); + + ValidateResult(test._fld1, test._fld2, result); + } + + public void RunFldScenario() + { + var result = Sse41.TestMixOnesZeros(_fld1, _fld2); + + ValidateResult(_fld1, _fld2, result); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128 left, Vector128 right, bool result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + Byte[] inArray2 = new Byte[Op2ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + + ValidateResult(inArray1, inArray2, result, method); + } + + private void ValidateResult(void* left, void* right, bool result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + Byte[] inArray2 = new Byte[Op2ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + + ValidateResult(inArray1, inArray2, result, method); + } + + private void ValidateResult(Byte[] left, Byte[] right, bool result, [CallerMemberName] string method = "") + { + var expectedResult1 = true; + + for (var i = 0; i < Op1ElementCount; i++) + { + expectedResult1 &= (((left[i] & right[i]) == 0)); + } + + var expectedResult2 = true; + + for (var i = 0; i < Op1ElementCount; i++) + { + expectedResult2 &= (((~left[i] & right[i]) == 0)); + } + + if (((expectedResult1 == false) && (expectedResult2 == false)) != result) + { + Succeeded = false; + + Console.WriteLine($"{nameof(Sse41)}.{nameof(Sse41.TestMixOnesZeros)}(Vector128, Vector128): {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/Sse41/TestMixOnesZeros.Int16.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestMixOnesZeros.Int16.cs new file mode 100644 index 000000000000..ef5d0860049a --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestMixOnesZeros.Int16.cs @@ -0,0 +1,313 @@ +// 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 TestMixOnesZerosInt16() + { + var test = new BooleanTwoComparisonOpTest__TestMixOnesZerosInt16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Sse2.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 (Sse2.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 (Sse2.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 BooleanTwoComparisonOpTest__TestMixOnesZerosInt16 + { + private const int VectorSize = 16; + + private const int Op1ElementCount = VectorSize / sizeof(Int16); + private const int Op2ElementCount = VectorSize / sizeof(Int16); + + private static Int16[] _data1 = new Int16[Op1ElementCount]; + private static Int16[] _data2 = new Int16[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private BooleanTwoComparisonOpTest__DataTable _dataTable; + + static BooleanTwoComparisonOpTest__TestMixOnesZerosInt16() + { + 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, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (short)(random.Next(short.MinValue, short.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), VectorSize); + } + + public BooleanTwoComparisonOpTest__TestMixOnesZerosInt16() + { + 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, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (short)(random.Next(short.MinValue, short.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), VectorSize); + + 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 BooleanTwoComparisonOpTest__DataTable(_data1, _data2, VectorSize); + } + + public bool IsSupported => Sse41.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse41.TestMixOnesZeros( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunBasicScenario_Load() + { + var result = Sse41.TestMixOnesZeros( + Sse2.LoadVector128((Int16*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Int16*)(_dataTable.inArray2Ptr)) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse41.TestMixOnesZeros( + Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray2Ptr)) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestMixOnesZeros), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestMixOnesZeros), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Int16*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Int16*)(_dataTable.inArray2Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestMixOnesZeros), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray2Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunClsVarScenario() + { + var result = Sse41.TestMixOnesZeros( + _clsVar1, + _clsVar2 + ); + + ValidateResult(_clsVar1, _clsVar2, result); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read>(_dataTable.inArray1Ptr); + var right = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = Sse41.TestMixOnesZeros(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((Int16*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((Int16*)(_dataTable.inArray2Ptr)); + var result = Sse41.TestMixOnesZeros(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray2Ptr)); + var result = Sse41.TestMixOnesZeros(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclFldScenario() + { + var test = new BooleanTwoComparisonOpTest__TestMixOnesZerosInt16(); + var result = Sse41.TestMixOnesZeros(test._fld1, test._fld2); + + ValidateResult(test._fld1, test._fld2, result); + } + + public void RunFldScenario() + { + var result = Sse41.TestMixOnesZeros(_fld1, _fld2); + + ValidateResult(_fld1, _fld2, result); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128 left, Vector128 right, bool result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + + ValidateResult(inArray1, inArray2, result, method); + } + + private void ValidateResult(void* left, void* right, bool result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + + ValidateResult(inArray1, inArray2, result, method); + } + + private void ValidateResult(Int16[] left, Int16[] right, bool result, [CallerMemberName] string method = "") + { + var expectedResult1 = true; + + for (var i = 0; i < Op1ElementCount; i++) + { + expectedResult1 &= (((left[i] & right[i]) == 0)); + } + + var expectedResult2 = true; + + for (var i = 0; i < Op1ElementCount; i++) + { + expectedResult2 &= (((~left[i] & right[i]) == 0)); + } + + if (((expectedResult1 == false) && (expectedResult2 == false)) != result) + { + Succeeded = false; + + Console.WriteLine($"{nameof(Sse41)}.{nameof(Sse41.TestMixOnesZeros)}(Vector128, Vector128): {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/Sse41/TestMixOnesZeros.Int32.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestMixOnesZeros.Int32.cs new file mode 100644 index 000000000000..e67b4bc3fb86 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestMixOnesZeros.Int32.cs @@ -0,0 +1,313 @@ +// 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 TestMixOnesZerosInt32() + { + var test = new BooleanTwoComparisonOpTest__TestMixOnesZerosInt32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Sse2.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 (Sse2.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 (Sse2.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 BooleanTwoComparisonOpTest__TestMixOnesZerosInt32 + { + private const int VectorSize = 16; + + private const int Op1ElementCount = VectorSize / sizeof(Int32); + private const int Op2ElementCount = VectorSize / sizeof(Int32); + + private static Int32[] _data1 = new Int32[Op1ElementCount]; + private static Int32[] _data2 = new Int32[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private BooleanTwoComparisonOpTest__DataTable _dataTable; + + static BooleanTwoComparisonOpTest__TestMixOnesZerosInt32() + { + 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, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (int)(random.Next(int.MinValue, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), VectorSize); + } + + public BooleanTwoComparisonOpTest__TestMixOnesZerosInt32() + { + 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, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (int)(random.Next(int.MinValue, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), VectorSize); + + 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 BooleanTwoComparisonOpTest__DataTable(_data1, _data2, VectorSize); + } + + public bool IsSupported => Sse41.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse41.TestMixOnesZeros( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunBasicScenario_Load() + { + var result = Sse41.TestMixOnesZeros( + Sse2.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Int32*)(_dataTable.inArray2Ptr)) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse41.TestMixOnesZeros( + Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray2Ptr)) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestMixOnesZeros), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestMixOnesZeros), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Int32*)(_dataTable.inArray2Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestMixOnesZeros), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray2Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunClsVarScenario() + { + var result = Sse41.TestMixOnesZeros( + _clsVar1, + _clsVar2 + ); + + ValidateResult(_clsVar1, _clsVar2, result); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read>(_dataTable.inArray1Ptr); + var right = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = Sse41.TestMixOnesZeros(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((Int32*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((Int32*)(_dataTable.inArray2Ptr)); + var result = Sse41.TestMixOnesZeros(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray2Ptr)); + var result = Sse41.TestMixOnesZeros(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclFldScenario() + { + var test = new BooleanTwoComparisonOpTest__TestMixOnesZerosInt32(); + var result = Sse41.TestMixOnesZeros(test._fld1, test._fld2); + + ValidateResult(test._fld1, test._fld2, result); + } + + public void RunFldScenario() + { + var result = Sse41.TestMixOnesZeros(_fld1, _fld2); + + ValidateResult(_fld1, _fld2, result); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128 left, Vector128 right, bool result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + + ValidateResult(inArray1, inArray2, result, method); + } + + private void ValidateResult(void* left, void* right, bool result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + + ValidateResult(inArray1, inArray2, result, method); + } + + private void ValidateResult(Int32[] left, Int32[] right, bool result, [CallerMemberName] string method = "") + { + var expectedResult1 = true; + + for (var i = 0; i < Op1ElementCount; i++) + { + expectedResult1 &= (((left[i] & right[i]) == 0)); + } + + var expectedResult2 = true; + + for (var i = 0; i < Op1ElementCount; i++) + { + expectedResult2 &= (((~left[i] & right[i]) == 0)); + } + + if (((expectedResult1 == false) && (expectedResult2 == false)) != result) + { + Succeeded = false; + + Console.WriteLine($"{nameof(Sse41)}.{nameof(Sse41.TestMixOnesZeros)}(Vector128, Vector128): {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/Sse41/TestMixOnesZeros.Int64.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestMixOnesZeros.Int64.cs new file mode 100644 index 000000000000..0fec963d86aa --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestMixOnesZeros.Int64.cs @@ -0,0 +1,313 @@ +// 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 TestMixOnesZerosInt64() + { + var test = new BooleanTwoComparisonOpTest__TestMixOnesZerosInt64(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Sse2.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 (Sse2.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 (Sse2.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 BooleanTwoComparisonOpTest__TestMixOnesZerosInt64 + { + private const int VectorSize = 16; + + private const int Op1ElementCount = VectorSize / sizeof(Int64); + private const int Op2ElementCount = VectorSize / sizeof(Int64); + + private static Int64[] _data1 = new Int64[Op1ElementCount]; + private static Int64[] _data2 = new Int64[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private BooleanTwoComparisonOpTest__DataTable _dataTable; + + static BooleanTwoComparisonOpTest__TestMixOnesZerosInt64() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (long)(random.Next(int.MinValue, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (long)(random.Next(int.MinValue, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), VectorSize); + } + + public BooleanTwoComparisonOpTest__TestMixOnesZerosInt64() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (long)(random.Next(int.MinValue, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (long)(random.Next(int.MinValue, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), VectorSize); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (long)(random.Next(int.MinValue, int.MaxValue)); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (long)(random.Next(int.MinValue, int.MaxValue)); } + _dataTable = new BooleanTwoComparisonOpTest__DataTable(_data1, _data2, VectorSize); + } + + public bool IsSupported => Sse41.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse41.TestMixOnesZeros( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunBasicScenario_Load() + { + var result = Sse41.TestMixOnesZeros( + Sse2.LoadVector128((Int64*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Int64*)(_dataTable.inArray2Ptr)) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse41.TestMixOnesZeros( + Sse2.LoadAlignedVector128((Int64*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Int64*)(_dataTable.inArray2Ptr)) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestMixOnesZeros), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestMixOnesZeros), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Int64*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Int64*)(_dataTable.inArray2Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestMixOnesZeros), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Int64*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Int64*)(_dataTable.inArray2Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunClsVarScenario() + { + var result = Sse41.TestMixOnesZeros( + _clsVar1, + _clsVar2 + ); + + ValidateResult(_clsVar1, _clsVar2, result); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read>(_dataTable.inArray1Ptr); + var right = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = Sse41.TestMixOnesZeros(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((Int64*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((Int64*)(_dataTable.inArray2Ptr)); + var result = Sse41.TestMixOnesZeros(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((Int64*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((Int64*)(_dataTable.inArray2Ptr)); + var result = Sse41.TestMixOnesZeros(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclFldScenario() + { + var test = new BooleanTwoComparisonOpTest__TestMixOnesZerosInt64(); + var result = Sse41.TestMixOnesZeros(test._fld1, test._fld2); + + ValidateResult(test._fld1, test._fld2, result); + } + + public void RunFldScenario() + { + var result = Sse41.TestMixOnesZeros(_fld1, _fld2); + + ValidateResult(_fld1, _fld2, result); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128 left, Vector128 right, bool result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + + ValidateResult(inArray1, inArray2, result, method); + } + + private void ValidateResult(void* left, void* right, bool result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + + ValidateResult(inArray1, inArray2, result, method); + } + + private void ValidateResult(Int64[] left, Int64[] right, bool result, [CallerMemberName] string method = "") + { + var expectedResult1 = true; + + for (var i = 0; i < Op1ElementCount; i++) + { + expectedResult1 &= (((left[i] & right[i]) == 0)); + } + + var expectedResult2 = true; + + for (var i = 0; i < Op1ElementCount; i++) + { + expectedResult2 &= (((~left[i] & right[i]) == 0)); + } + + if (((expectedResult1 == false) && (expectedResult2 == false)) != result) + { + Succeeded = false; + + Console.WriteLine($"{nameof(Sse41)}.{nameof(Sse41.TestMixOnesZeros)}(Vector128, Vector128): {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/Sse41/TestMixOnesZeros.SByte.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestMixOnesZeros.SByte.cs new file mode 100644 index 000000000000..cc4853d33153 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestMixOnesZeros.SByte.cs @@ -0,0 +1,313 @@ +// 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 TestMixOnesZerosSByte() + { + var test = new BooleanTwoComparisonOpTest__TestMixOnesZerosSByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Sse2.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 (Sse2.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 (Sse2.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 BooleanTwoComparisonOpTest__TestMixOnesZerosSByte + { + private const int VectorSize = 16; + + private const int Op1ElementCount = VectorSize / sizeof(SByte); + private const int Op2ElementCount = VectorSize / sizeof(SByte); + + private static SByte[] _data1 = new SByte[Op1ElementCount]; + private static SByte[] _data2 = new SByte[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private BooleanTwoComparisonOpTest__DataTable _dataTable; + + static BooleanTwoComparisonOpTest__TestMixOnesZerosSByte() + { + 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, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), VectorSize); + } + + public BooleanTwoComparisonOpTest__TestMixOnesZerosSByte() + { + 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, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), VectorSize); + + 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 BooleanTwoComparisonOpTest__DataTable(_data1, _data2, VectorSize); + } + + public bool IsSupported => Sse41.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse41.TestMixOnesZeros( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunBasicScenario_Load() + { + var result = Sse41.TestMixOnesZeros( + Sse2.LoadVector128((SByte*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((SByte*)(_dataTable.inArray2Ptr)) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse41.TestMixOnesZeros( + Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArray2Ptr)) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestMixOnesZeros), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestMixOnesZeros), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((SByte*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((SByte*)(_dataTable.inArray2Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestMixOnesZeros), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArray2Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunClsVarScenario() + { + var result = Sse41.TestMixOnesZeros( + _clsVar1, + _clsVar2 + ); + + ValidateResult(_clsVar1, _clsVar2, result); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read>(_dataTable.inArray1Ptr); + var right = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = Sse41.TestMixOnesZeros(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((SByte*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((SByte*)(_dataTable.inArray2Ptr)); + var result = Sse41.TestMixOnesZeros(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArray2Ptr)); + var result = Sse41.TestMixOnesZeros(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclFldScenario() + { + var test = new BooleanTwoComparisonOpTest__TestMixOnesZerosSByte(); + var result = Sse41.TestMixOnesZeros(test._fld1, test._fld2); + + ValidateResult(test._fld1, test._fld2, result); + } + + public void RunFldScenario() + { + var result = Sse41.TestMixOnesZeros(_fld1, _fld2); + + ValidateResult(_fld1, _fld2, result); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128 left, Vector128 right, bool result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + + ValidateResult(inArray1, inArray2, result, method); + } + + private void ValidateResult(void* left, void* right, bool result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + + ValidateResult(inArray1, inArray2, result, method); + } + + private void ValidateResult(SByte[] left, SByte[] right, bool result, [CallerMemberName] string method = "") + { + var expectedResult1 = true; + + for (var i = 0; i < Op1ElementCount; i++) + { + expectedResult1 &= (((left[i] & right[i]) == 0)); + } + + var expectedResult2 = true; + + for (var i = 0; i < Op1ElementCount; i++) + { + expectedResult2 &= (((~left[i] & right[i]) == 0)); + } + + if (((expectedResult1 == false) && (expectedResult2 == false)) != result) + { + Succeeded = false; + + Console.WriteLine($"{nameof(Sse41)}.{nameof(Sse41.TestMixOnesZeros)}(Vector128, Vector128): {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/Sse41/TestMixOnesZeros.UInt16.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestMixOnesZeros.UInt16.cs new file mode 100644 index 000000000000..d0282f8b4168 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestMixOnesZeros.UInt16.cs @@ -0,0 +1,313 @@ +// 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 TestMixOnesZerosUInt16() + { + var test = new BooleanTwoComparisonOpTest__TestMixOnesZerosUInt16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Sse2.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 (Sse2.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 (Sse2.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 BooleanTwoComparisonOpTest__TestMixOnesZerosUInt16 + { + private const int VectorSize = 16; + + private const int Op1ElementCount = VectorSize / sizeof(UInt16); + private const int Op2ElementCount = VectorSize / sizeof(UInt16); + + private static UInt16[] _data1 = new UInt16[Op1ElementCount]; + private static UInt16[] _data2 = new UInt16[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private BooleanTwoComparisonOpTest__DataTable _dataTable; + + static BooleanTwoComparisonOpTest__TestMixOnesZerosUInt16() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (ushort)(random.Next(0, ushort.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (ushort)(random.Next(0, ushort.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), VectorSize); + } + + public BooleanTwoComparisonOpTest__TestMixOnesZerosUInt16() + { + 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, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (ushort)(random.Next(0, ushort.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), VectorSize); + + 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 BooleanTwoComparisonOpTest__DataTable(_data1, _data2, VectorSize); + } + + public bool IsSupported => Sse41.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse41.TestMixOnesZeros( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunBasicScenario_Load() + { + var result = Sse41.TestMixOnesZeros( + Sse2.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse41.TestMixOnesZeros( + Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArray2Ptr)) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestMixOnesZeros), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestMixOnesZeros), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestMixOnesZeros), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArray2Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunClsVarScenario() + { + var result = Sse41.TestMixOnesZeros( + _clsVar1, + _clsVar2 + ); + + ValidateResult(_clsVar1, _clsVar2, result); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read>(_dataTable.inArray1Ptr); + var right = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = Sse41.TestMixOnesZeros(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)); + var result = Sse41.TestMixOnesZeros(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArray2Ptr)); + var result = Sse41.TestMixOnesZeros(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclFldScenario() + { + var test = new BooleanTwoComparisonOpTest__TestMixOnesZerosUInt16(); + var result = Sse41.TestMixOnesZeros(test._fld1, test._fld2); + + ValidateResult(test._fld1, test._fld2, result); + } + + public void RunFldScenario() + { + var result = Sse41.TestMixOnesZeros(_fld1, _fld2); + + ValidateResult(_fld1, _fld2, result); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128 left, Vector128 right, bool result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + + ValidateResult(inArray1, inArray2, result, method); + } + + private void ValidateResult(void* left, void* right, bool result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + + ValidateResult(inArray1, inArray2, result, method); + } + + private void ValidateResult(UInt16[] left, UInt16[] right, bool result, [CallerMemberName] string method = "") + { + var expectedResult1 = true; + + for (var i = 0; i < Op1ElementCount; i++) + { + expectedResult1 &= (((left[i] & right[i]) == 0)); + } + + var expectedResult2 = true; + + for (var i = 0; i < Op1ElementCount; i++) + { + expectedResult2 &= (((~left[i] & right[i]) == 0)); + } + + if (((expectedResult1 == false) && (expectedResult2 == false)) != result) + { + Succeeded = false; + + Console.WriteLine($"{nameof(Sse41)}.{nameof(Sse41.TestMixOnesZeros)}(Vector128, Vector128): {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/Sse41/TestMixOnesZeros.UInt32.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestMixOnesZeros.UInt32.cs new file mode 100644 index 000000000000..cc60c2f1a398 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestMixOnesZeros.UInt32.cs @@ -0,0 +1,313 @@ +// 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 TestMixOnesZerosUInt32() + { + var test = new BooleanTwoComparisonOpTest__TestMixOnesZerosUInt32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Sse2.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 (Sse2.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 (Sse2.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 BooleanTwoComparisonOpTest__TestMixOnesZerosUInt32 + { + private const int VectorSize = 16; + + private const int Op1ElementCount = VectorSize / sizeof(UInt32); + private const int Op2ElementCount = VectorSize / sizeof(UInt32); + + private static UInt32[] _data1 = new UInt32[Op1ElementCount]; + private static UInt32[] _data2 = new UInt32[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private BooleanTwoComparisonOpTest__DataTable _dataTable; + + static BooleanTwoComparisonOpTest__TestMixOnesZerosUInt32() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (uint)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (uint)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), VectorSize); + } + + public BooleanTwoComparisonOpTest__TestMixOnesZerosUInt32() + { + 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, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (uint)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(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 BooleanTwoComparisonOpTest__DataTable(_data1, _data2, VectorSize); + } + + public bool IsSupported => Sse41.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse41.TestMixOnesZeros( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunBasicScenario_Load() + { + var result = Sse41.TestMixOnesZeros( + Sse2.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse41.TestMixOnesZeros( + Sse2.LoadAlignedVector128((UInt32*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((UInt32*)(_dataTable.inArray2Ptr)) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestMixOnesZeros), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestMixOnesZeros), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestMixOnesZeros), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((UInt32*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((UInt32*)(_dataTable.inArray2Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunClsVarScenario() + { + var result = Sse41.TestMixOnesZeros( + _clsVar1, + _clsVar2 + ); + + ValidateResult(_clsVar1, _clsVar2, result); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read>(_dataTable.inArray1Ptr); + var right = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = Sse41.TestMixOnesZeros(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)); + var result = Sse41.TestMixOnesZeros(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((UInt32*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((UInt32*)(_dataTable.inArray2Ptr)); + var result = Sse41.TestMixOnesZeros(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclFldScenario() + { + var test = new BooleanTwoComparisonOpTest__TestMixOnesZerosUInt32(); + var result = Sse41.TestMixOnesZeros(test._fld1, test._fld2); + + ValidateResult(test._fld1, test._fld2, result); + } + + public void RunFldScenario() + { + var result = Sse41.TestMixOnesZeros(_fld1, _fld2); + + ValidateResult(_fld1, _fld2, result); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128 left, Vector128 right, bool result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + + ValidateResult(inArray1, inArray2, result, method); + } + + private void ValidateResult(void* left, void* right, bool result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + + ValidateResult(inArray1, inArray2, result, method); + } + + private void ValidateResult(UInt32[] left, UInt32[] right, bool result, [CallerMemberName] string method = "") + { + var expectedResult1 = true; + + for (var i = 0; i < Op1ElementCount; i++) + { + expectedResult1 &= (((left[i] & right[i]) == 0)); + } + + var expectedResult2 = true; + + for (var i = 0; i < Op1ElementCount; i++) + { + expectedResult2 &= (((~left[i] & right[i]) == 0)); + } + + if (((expectedResult1 == false) && (expectedResult2 == false)) != result) + { + Succeeded = false; + + Console.WriteLine($"{nameof(Sse41)}.{nameof(Sse41.TestMixOnesZeros)}(Vector128, Vector128): {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/Sse41/TestMixOnesZeros.UInt64.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestMixOnesZeros.UInt64.cs new file mode 100644 index 000000000000..4d9915b88316 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestMixOnesZeros.UInt64.cs @@ -0,0 +1,313 @@ +// 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 TestMixOnesZerosUInt64() + { + var test = new BooleanTwoComparisonOpTest__TestMixOnesZerosUInt64(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Sse2.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 (Sse2.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 (Sse2.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 BooleanTwoComparisonOpTest__TestMixOnesZerosUInt64 + { + private const int VectorSize = 16; + + private const int Op1ElementCount = VectorSize / sizeof(UInt64); + private const int Op2ElementCount = VectorSize / sizeof(UInt64); + + private static UInt64[] _data1 = new UInt64[Op1ElementCount]; + private static UInt64[] _data2 = new UInt64[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private BooleanTwoComparisonOpTest__DataTable _dataTable; + + static BooleanTwoComparisonOpTest__TestMixOnesZerosUInt64() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (ulong)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (ulong)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), VectorSize); + } + + public BooleanTwoComparisonOpTest__TestMixOnesZerosUInt64() + { + 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, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (ulong)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(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 BooleanTwoComparisonOpTest__DataTable(_data1, _data2, VectorSize); + } + + public bool IsSupported => Sse41.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse41.TestMixOnesZeros( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunBasicScenario_Load() + { + var result = Sse41.TestMixOnesZeros( + Sse2.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((UInt64*)(_dataTable.inArray2Ptr)) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse41.TestMixOnesZeros( + Sse2.LoadAlignedVector128((UInt64*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((UInt64*)(_dataTable.inArray2Ptr)) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestMixOnesZeros), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestMixOnesZeros), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((UInt64*)(_dataTable.inArray2Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestMixOnesZeros), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((UInt64*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((UInt64*)(_dataTable.inArray2Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunClsVarScenario() + { + var result = Sse41.TestMixOnesZeros( + _clsVar1, + _clsVar2 + ); + + ValidateResult(_clsVar1, _clsVar2, result); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read>(_dataTable.inArray1Ptr); + var right = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = Sse41.TestMixOnesZeros(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((UInt64*)(_dataTable.inArray2Ptr)); + var result = Sse41.TestMixOnesZeros(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((UInt64*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((UInt64*)(_dataTable.inArray2Ptr)); + var result = Sse41.TestMixOnesZeros(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclFldScenario() + { + var test = new BooleanTwoComparisonOpTest__TestMixOnesZerosUInt64(); + var result = Sse41.TestMixOnesZeros(test._fld1, test._fld2); + + ValidateResult(test._fld1, test._fld2, result); + } + + public void RunFldScenario() + { + var result = Sse41.TestMixOnesZeros(_fld1, _fld2); + + ValidateResult(_fld1, _fld2, result); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128 left, Vector128 right, bool result, [CallerMemberName] string method = "") + { + UInt64[] inArray1 = new UInt64[Op1ElementCount]; + UInt64[] inArray2 = new UInt64[Op2ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + + ValidateResult(inArray1, inArray2, result, method); + } + + private void ValidateResult(void* left, void* right, bool result, [CallerMemberName] string method = "") + { + UInt64[] inArray1 = new UInt64[Op1ElementCount]; + UInt64[] inArray2 = new UInt64[Op2ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + + ValidateResult(inArray1, inArray2, result, method); + } + + private void ValidateResult(UInt64[] left, UInt64[] right, bool result, [CallerMemberName] string method = "") + { + var expectedResult1 = true; + + for (var i = 0; i < Op1ElementCount; i++) + { + expectedResult1 &= (((left[i] & right[i]) == 0)); + } + + var expectedResult2 = true; + + for (var i = 0; i < Op1ElementCount; i++) + { + expectedResult2 &= (((~left[i] & right[i]) == 0)); + } + + if (((expectedResult1 == false) && (expectedResult2 == false)) != result) + { + Succeeded = false; + + Console.WriteLine($"{nameof(Sse41)}.{nameof(Sse41.TestMixOnesZeros)}(Vector128, Vector128): {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/Sse41/TestNotZAndNotC.Byte.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestNotZAndNotC.Byte.cs new file mode 100644 index 000000000000..1bb8e7507061 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestNotZAndNotC.Byte.cs @@ -0,0 +1,313 @@ +// 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 TestNotZAndNotCByte() + { + var test = new BooleanTwoComparisonOpTest__TestNotZAndNotCByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Sse2.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 (Sse2.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 (Sse2.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 BooleanTwoComparisonOpTest__TestNotZAndNotCByte + { + private const int VectorSize = 16; + + private const int Op1ElementCount = VectorSize / sizeof(Byte); + private const int Op2ElementCount = VectorSize / sizeof(Byte); + + private static Byte[] _data1 = new Byte[Op1ElementCount]; + private static Byte[] _data2 = new Byte[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private BooleanTwoComparisonOpTest__DataTable _dataTable; + + static BooleanTwoComparisonOpTest__TestNotZAndNotCByte() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (byte)(random.Next(0, byte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (byte)(random.Next(0, byte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), VectorSize); + } + + public BooleanTwoComparisonOpTest__TestNotZAndNotCByte() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (byte)(random.Next(0, byte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (byte)(random.Next(0, byte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), VectorSize); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (byte)(random.Next(0, byte.MaxValue)); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (byte)(random.Next(0, byte.MaxValue)); } + _dataTable = new BooleanTwoComparisonOpTest__DataTable(_data1, _data2, VectorSize); + } + + public bool IsSupported => Sse41.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse41.TestNotZAndNotC( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunBasicScenario_Load() + { + var result = Sse41.TestNotZAndNotC( + Sse2.LoadVector128((Byte*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Byte*)(_dataTable.inArray2Ptr)) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse41.TestNotZAndNotC( + Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray2Ptr)) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestNotZAndNotC), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestNotZAndNotC), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Byte*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Byte*)(_dataTable.inArray2Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestNotZAndNotC), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray2Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunClsVarScenario() + { + var result = Sse41.TestNotZAndNotC( + _clsVar1, + _clsVar2 + ); + + ValidateResult(_clsVar1, _clsVar2, result); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read>(_dataTable.inArray1Ptr); + var right = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = Sse41.TestNotZAndNotC(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((Byte*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((Byte*)(_dataTable.inArray2Ptr)); + var result = Sse41.TestNotZAndNotC(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray2Ptr)); + var result = Sse41.TestNotZAndNotC(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclFldScenario() + { + var test = new BooleanTwoComparisonOpTest__TestNotZAndNotCByte(); + var result = Sse41.TestNotZAndNotC(test._fld1, test._fld2); + + ValidateResult(test._fld1, test._fld2, result); + } + + public void RunFldScenario() + { + var result = Sse41.TestNotZAndNotC(_fld1, _fld2); + + ValidateResult(_fld1, _fld2, result); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128 left, Vector128 right, bool result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + Byte[] inArray2 = new Byte[Op2ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + + ValidateResult(inArray1, inArray2, result, method); + } + + private void ValidateResult(void* left, void* right, bool result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + Byte[] inArray2 = new Byte[Op2ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + + ValidateResult(inArray1, inArray2, result, method); + } + + private void ValidateResult(Byte[] left, Byte[] right, bool result, [CallerMemberName] string method = "") + { + var expectedResult1 = true; + + for (var i = 0; i < Op1ElementCount; i++) + { + expectedResult1 &= (((left[i] & right[i]) == 0)); + } + + var expectedResult2 = true; + + for (var i = 0; i < Op1ElementCount; i++) + { + expectedResult2 &= (((~left[i] & right[i]) == 0)); + } + + if (((expectedResult1 == false) && (expectedResult2 == false)) != result) + { + Succeeded = false; + + Console.WriteLine($"{nameof(Sse41)}.{nameof(Sse41.TestNotZAndNotC)}(Vector128, Vector128): {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/Sse41/TestNotZAndNotC.Int16.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestNotZAndNotC.Int16.cs new file mode 100644 index 000000000000..6528e379adc3 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestNotZAndNotC.Int16.cs @@ -0,0 +1,313 @@ +// 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 TestNotZAndNotCInt16() + { + var test = new BooleanTwoComparisonOpTest__TestNotZAndNotCInt16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Sse2.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 (Sse2.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 (Sse2.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 BooleanTwoComparisonOpTest__TestNotZAndNotCInt16 + { + private const int VectorSize = 16; + + private const int Op1ElementCount = VectorSize / sizeof(Int16); + private const int Op2ElementCount = VectorSize / sizeof(Int16); + + private static Int16[] _data1 = new Int16[Op1ElementCount]; + private static Int16[] _data2 = new Int16[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private BooleanTwoComparisonOpTest__DataTable _dataTable; + + static BooleanTwoComparisonOpTest__TestNotZAndNotCInt16() + { + 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, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (short)(random.Next(short.MinValue, short.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), VectorSize); + } + + public BooleanTwoComparisonOpTest__TestNotZAndNotCInt16() + { + 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, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (short)(random.Next(short.MinValue, short.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), VectorSize); + + 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 BooleanTwoComparisonOpTest__DataTable(_data1, _data2, VectorSize); + } + + public bool IsSupported => Sse41.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse41.TestNotZAndNotC( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunBasicScenario_Load() + { + var result = Sse41.TestNotZAndNotC( + Sse2.LoadVector128((Int16*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Int16*)(_dataTable.inArray2Ptr)) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse41.TestNotZAndNotC( + Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray2Ptr)) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestNotZAndNotC), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestNotZAndNotC), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Int16*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Int16*)(_dataTable.inArray2Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestNotZAndNotC), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray2Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunClsVarScenario() + { + var result = Sse41.TestNotZAndNotC( + _clsVar1, + _clsVar2 + ); + + ValidateResult(_clsVar1, _clsVar2, result); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read>(_dataTable.inArray1Ptr); + var right = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = Sse41.TestNotZAndNotC(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((Int16*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((Int16*)(_dataTable.inArray2Ptr)); + var result = Sse41.TestNotZAndNotC(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray2Ptr)); + var result = Sse41.TestNotZAndNotC(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclFldScenario() + { + var test = new BooleanTwoComparisonOpTest__TestNotZAndNotCInt16(); + var result = Sse41.TestNotZAndNotC(test._fld1, test._fld2); + + ValidateResult(test._fld1, test._fld2, result); + } + + public void RunFldScenario() + { + var result = Sse41.TestNotZAndNotC(_fld1, _fld2); + + ValidateResult(_fld1, _fld2, result); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128 left, Vector128 right, bool result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + + ValidateResult(inArray1, inArray2, result, method); + } + + private void ValidateResult(void* left, void* right, bool result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + + ValidateResult(inArray1, inArray2, result, method); + } + + private void ValidateResult(Int16[] left, Int16[] right, bool result, [CallerMemberName] string method = "") + { + var expectedResult1 = true; + + for (var i = 0; i < Op1ElementCount; i++) + { + expectedResult1 &= (((left[i] & right[i]) == 0)); + } + + var expectedResult2 = true; + + for (var i = 0; i < Op1ElementCount; i++) + { + expectedResult2 &= (((~left[i] & right[i]) == 0)); + } + + if (((expectedResult1 == false) && (expectedResult2 == false)) != result) + { + Succeeded = false; + + Console.WriteLine($"{nameof(Sse41)}.{nameof(Sse41.TestNotZAndNotC)}(Vector128, Vector128): {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/Sse41/TestNotZAndNotC.Int32.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestNotZAndNotC.Int32.cs new file mode 100644 index 000000000000..f8fd520c87fb --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestNotZAndNotC.Int32.cs @@ -0,0 +1,313 @@ +// 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 TestNotZAndNotCInt32() + { + var test = new BooleanTwoComparisonOpTest__TestNotZAndNotCInt32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Sse2.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 (Sse2.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 (Sse2.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 BooleanTwoComparisonOpTest__TestNotZAndNotCInt32 + { + private const int VectorSize = 16; + + private const int Op1ElementCount = VectorSize / sizeof(Int32); + private const int Op2ElementCount = VectorSize / sizeof(Int32); + + private static Int32[] _data1 = new Int32[Op1ElementCount]; + private static Int32[] _data2 = new Int32[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private BooleanTwoComparisonOpTest__DataTable _dataTable; + + static BooleanTwoComparisonOpTest__TestNotZAndNotCInt32() + { + 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, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (int)(random.Next(int.MinValue, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), VectorSize); + } + + public BooleanTwoComparisonOpTest__TestNotZAndNotCInt32() + { + 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, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (int)(random.Next(int.MinValue, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), VectorSize); + + 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 BooleanTwoComparisonOpTest__DataTable(_data1, _data2, VectorSize); + } + + public bool IsSupported => Sse41.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse41.TestNotZAndNotC( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunBasicScenario_Load() + { + var result = Sse41.TestNotZAndNotC( + Sse2.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Int32*)(_dataTable.inArray2Ptr)) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse41.TestNotZAndNotC( + Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray2Ptr)) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestNotZAndNotC), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestNotZAndNotC), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Int32*)(_dataTable.inArray2Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestNotZAndNotC), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray2Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunClsVarScenario() + { + var result = Sse41.TestNotZAndNotC( + _clsVar1, + _clsVar2 + ); + + ValidateResult(_clsVar1, _clsVar2, result); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read>(_dataTable.inArray1Ptr); + var right = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = Sse41.TestNotZAndNotC(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((Int32*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((Int32*)(_dataTable.inArray2Ptr)); + var result = Sse41.TestNotZAndNotC(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray2Ptr)); + var result = Sse41.TestNotZAndNotC(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclFldScenario() + { + var test = new BooleanTwoComparisonOpTest__TestNotZAndNotCInt32(); + var result = Sse41.TestNotZAndNotC(test._fld1, test._fld2); + + ValidateResult(test._fld1, test._fld2, result); + } + + public void RunFldScenario() + { + var result = Sse41.TestNotZAndNotC(_fld1, _fld2); + + ValidateResult(_fld1, _fld2, result); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128 left, Vector128 right, bool result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + + ValidateResult(inArray1, inArray2, result, method); + } + + private void ValidateResult(void* left, void* right, bool result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + + ValidateResult(inArray1, inArray2, result, method); + } + + private void ValidateResult(Int32[] left, Int32[] right, bool result, [CallerMemberName] string method = "") + { + var expectedResult1 = true; + + for (var i = 0; i < Op1ElementCount; i++) + { + expectedResult1 &= (((left[i] & right[i]) == 0)); + } + + var expectedResult2 = true; + + for (var i = 0; i < Op1ElementCount; i++) + { + expectedResult2 &= (((~left[i] & right[i]) == 0)); + } + + if (((expectedResult1 == false) && (expectedResult2 == false)) != result) + { + Succeeded = false; + + Console.WriteLine($"{nameof(Sse41)}.{nameof(Sse41.TestNotZAndNotC)}(Vector128, Vector128): {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/Sse41/TestNotZAndNotC.Int64.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestNotZAndNotC.Int64.cs new file mode 100644 index 000000000000..1d1066e09c48 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestNotZAndNotC.Int64.cs @@ -0,0 +1,313 @@ +// 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 TestNotZAndNotCInt64() + { + var test = new BooleanTwoComparisonOpTest__TestNotZAndNotCInt64(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Sse2.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 (Sse2.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 (Sse2.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 BooleanTwoComparisonOpTest__TestNotZAndNotCInt64 + { + private const int VectorSize = 16; + + private const int Op1ElementCount = VectorSize / sizeof(Int64); + private const int Op2ElementCount = VectorSize / sizeof(Int64); + + private static Int64[] _data1 = new Int64[Op1ElementCount]; + private static Int64[] _data2 = new Int64[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private BooleanTwoComparisonOpTest__DataTable _dataTable; + + static BooleanTwoComparisonOpTest__TestNotZAndNotCInt64() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (long)(random.Next(int.MinValue, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (long)(random.Next(int.MinValue, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), VectorSize); + } + + public BooleanTwoComparisonOpTest__TestNotZAndNotCInt64() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (long)(random.Next(int.MinValue, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (long)(random.Next(int.MinValue, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), VectorSize); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (long)(random.Next(int.MinValue, int.MaxValue)); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (long)(random.Next(int.MinValue, int.MaxValue)); } + _dataTable = new BooleanTwoComparisonOpTest__DataTable(_data1, _data2, VectorSize); + } + + public bool IsSupported => Sse41.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse41.TestNotZAndNotC( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunBasicScenario_Load() + { + var result = Sse41.TestNotZAndNotC( + Sse2.LoadVector128((Int64*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Int64*)(_dataTable.inArray2Ptr)) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse41.TestNotZAndNotC( + Sse2.LoadAlignedVector128((Int64*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Int64*)(_dataTable.inArray2Ptr)) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestNotZAndNotC), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestNotZAndNotC), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Int64*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Int64*)(_dataTable.inArray2Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestNotZAndNotC), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Int64*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Int64*)(_dataTable.inArray2Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunClsVarScenario() + { + var result = Sse41.TestNotZAndNotC( + _clsVar1, + _clsVar2 + ); + + ValidateResult(_clsVar1, _clsVar2, result); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read>(_dataTable.inArray1Ptr); + var right = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = Sse41.TestNotZAndNotC(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((Int64*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((Int64*)(_dataTable.inArray2Ptr)); + var result = Sse41.TestNotZAndNotC(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((Int64*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((Int64*)(_dataTable.inArray2Ptr)); + var result = Sse41.TestNotZAndNotC(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclFldScenario() + { + var test = new BooleanTwoComparisonOpTest__TestNotZAndNotCInt64(); + var result = Sse41.TestNotZAndNotC(test._fld1, test._fld2); + + ValidateResult(test._fld1, test._fld2, result); + } + + public void RunFldScenario() + { + var result = Sse41.TestNotZAndNotC(_fld1, _fld2); + + ValidateResult(_fld1, _fld2, result); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128 left, Vector128 right, bool result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + + ValidateResult(inArray1, inArray2, result, method); + } + + private void ValidateResult(void* left, void* right, bool result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + + ValidateResult(inArray1, inArray2, result, method); + } + + private void ValidateResult(Int64[] left, Int64[] right, bool result, [CallerMemberName] string method = "") + { + var expectedResult1 = true; + + for (var i = 0; i < Op1ElementCount; i++) + { + expectedResult1 &= (((left[i] & right[i]) == 0)); + } + + var expectedResult2 = true; + + for (var i = 0; i < Op1ElementCount; i++) + { + expectedResult2 &= (((~left[i] & right[i]) == 0)); + } + + if (((expectedResult1 == false) && (expectedResult2 == false)) != result) + { + Succeeded = false; + + Console.WriteLine($"{nameof(Sse41)}.{nameof(Sse41.TestNotZAndNotC)}(Vector128, Vector128): {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/Sse41/TestNotZAndNotC.SByte.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestNotZAndNotC.SByte.cs new file mode 100644 index 000000000000..87d0d9eee620 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestNotZAndNotC.SByte.cs @@ -0,0 +1,313 @@ +// 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 TestNotZAndNotCSByte() + { + var test = new BooleanTwoComparisonOpTest__TestNotZAndNotCSByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Sse2.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 (Sse2.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 (Sse2.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 BooleanTwoComparisonOpTest__TestNotZAndNotCSByte + { + private const int VectorSize = 16; + + private const int Op1ElementCount = VectorSize / sizeof(SByte); + private const int Op2ElementCount = VectorSize / sizeof(SByte); + + private static SByte[] _data1 = new SByte[Op1ElementCount]; + private static SByte[] _data2 = new SByte[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private BooleanTwoComparisonOpTest__DataTable _dataTable; + + static BooleanTwoComparisonOpTest__TestNotZAndNotCSByte() + { + 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, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), VectorSize); + } + + public BooleanTwoComparisonOpTest__TestNotZAndNotCSByte() + { + 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, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), VectorSize); + + 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 BooleanTwoComparisonOpTest__DataTable(_data1, _data2, VectorSize); + } + + public bool IsSupported => Sse41.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse41.TestNotZAndNotC( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunBasicScenario_Load() + { + var result = Sse41.TestNotZAndNotC( + Sse2.LoadVector128((SByte*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((SByte*)(_dataTable.inArray2Ptr)) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse41.TestNotZAndNotC( + Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArray2Ptr)) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestNotZAndNotC), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestNotZAndNotC), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((SByte*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((SByte*)(_dataTable.inArray2Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestNotZAndNotC), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArray2Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunClsVarScenario() + { + var result = Sse41.TestNotZAndNotC( + _clsVar1, + _clsVar2 + ); + + ValidateResult(_clsVar1, _clsVar2, result); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read>(_dataTable.inArray1Ptr); + var right = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = Sse41.TestNotZAndNotC(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((SByte*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((SByte*)(_dataTable.inArray2Ptr)); + var result = Sse41.TestNotZAndNotC(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArray2Ptr)); + var result = Sse41.TestNotZAndNotC(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclFldScenario() + { + var test = new BooleanTwoComparisonOpTest__TestNotZAndNotCSByte(); + var result = Sse41.TestNotZAndNotC(test._fld1, test._fld2); + + ValidateResult(test._fld1, test._fld2, result); + } + + public void RunFldScenario() + { + var result = Sse41.TestNotZAndNotC(_fld1, _fld2); + + ValidateResult(_fld1, _fld2, result); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128 left, Vector128 right, bool result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + + ValidateResult(inArray1, inArray2, result, method); + } + + private void ValidateResult(void* left, void* right, bool result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + + ValidateResult(inArray1, inArray2, result, method); + } + + private void ValidateResult(SByte[] left, SByte[] right, bool result, [CallerMemberName] string method = "") + { + var expectedResult1 = true; + + for (var i = 0; i < Op1ElementCount; i++) + { + expectedResult1 &= (((left[i] & right[i]) == 0)); + } + + var expectedResult2 = true; + + for (var i = 0; i < Op1ElementCount; i++) + { + expectedResult2 &= (((~left[i] & right[i]) == 0)); + } + + if (((expectedResult1 == false) && (expectedResult2 == false)) != result) + { + Succeeded = false; + + Console.WriteLine($"{nameof(Sse41)}.{nameof(Sse41.TestNotZAndNotC)}(Vector128, Vector128): {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/Sse41/TestNotZAndNotC.UInt16.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestNotZAndNotC.UInt16.cs new file mode 100644 index 000000000000..9e5d75666dc4 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestNotZAndNotC.UInt16.cs @@ -0,0 +1,313 @@ +// 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 TestNotZAndNotCUInt16() + { + var test = new BooleanTwoComparisonOpTest__TestNotZAndNotCUInt16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Sse2.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 (Sse2.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 (Sse2.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 BooleanTwoComparisonOpTest__TestNotZAndNotCUInt16 + { + private const int VectorSize = 16; + + private const int Op1ElementCount = VectorSize / sizeof(UInt16); + private const int Op2ElementCount = VectorSize / sizeof(UInt16); + + private static UInt16[] _data1 = new UInt16[Op1ElementCount]; + private static UInt16[] _data2 = new UInt16[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private BooleanTwoComparisonOpTest__DataTable _dataTable; + + static BooleanTwoComparisonOpTest__TestNotZAndNotCUInt16() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (ushort)(random.Next(0, ushort.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (ushort)(random.Next(0, ushort.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), VectorSize); + } + + public BooleanTwoComparisonOpTest__TestNotZAndNotCUInt16() + { + 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, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (ushort)(random.Next(0, ushort.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), VectorSize); + + 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 BooleanTwoComparisonOpTest__DataTable(_data1, _data2, VectorSize); + } + + public bool IsSupported => Sse41.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse41.TestNotZAndNotC( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunBasicScenario_Load() + { + var result = Sse41.TestNotZAndNotC( + Sse2.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse41.TestNotZAndNotC( + Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArray2Ptr)) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestNotZAndNotC), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestNotZAndNotC), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestNotZAndNotC), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArray2Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunClsVarScenario() + { + var result = Sse41.TestNotZAndNotC( + _clsVar1, + _clsVar2 + ); + + ValidateResult(_clsVar1, _clsVar2, result); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read>(_dataTable.inArray1Ptr); + var right = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = Sse41.TestNotZAndNotC(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)); + var result = Sse41.TestNotZAndNotC(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArray2Ptr)); + var result = Sse41.TestNotZAndNotC(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclFldScenario() + { + var test = new BooleanTwoComparisonOpTest__TestNotZAndNotCUInt16(); + var result = Sse41.TestNotZAndNotC(test._fld1, test._fld2); + + ValidateResult(test._fld1, test._fld2, result); + } + + public void RunFldScenario() + { + var result = Sse41.TestNotZAndNotC(_fld1, _fld2); + + ValidateResult(_fld1, _fld2, result); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128 left, Vector128 right, bool result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + + ValidateResult(inArray1, inArray2, result, method); + } + + private void ValidateResult(void* left, void* right, bool result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + + ValidateResult(inArray1, inArray2, result, method); + } + + private void ValidateResult(UInt16[] left, UInt16[] right, bool result, [CallerMemberName] string method = "") + { + var expectedResult1 = true; + + for (var i = 0; i < Op1ElementCount; i++) + { + expectedResult1 &= (((left[i] & right[i]) == 0)); + } + + var expectedResult2 = true; + + for (var i = 0; i < Op1ElementCount; i++) + { + expectedResult2 &= (((~left[i] & right[i]) == 0)); + } + + if (((expectedResult1 == false) && (expectedResult2 == false)) != result) + { + Succeeded = false; + + Console.WriteLine($"{nameof(Sse41)}.{nameof(Sse41.TestNotZAndNotC)}(Vector128, Vector128): {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/Sse41/TestNotZAndNotC.UInt32.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestNotZAndNotC.UInt32.cs new file mode 100644 index 000000000000..4730e23b7e29 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestNotZAndNotC.UInt32.cs @@ -0,0 +1,313 @@ +// 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 TestNotZAndNotCUInt32() + { + var test = new BooleanTwoComparisonOpTest__TestNotZAndNotCUInt32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Sse2.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 (Sse2.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 (Sse2.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 BooleanTwoComparisonOpTest__TestNotZAndNotCUInt32 + { + private const int VectorSize = 16; + + private const int Op1ElementCount = VectorSize / sizeof(UInt32); + private const int Op2ElementCount = VectorSize / sizeof(UInt32); + + private static UInt32[] _data1 = new UInt32[Op1ElementCount]; + private static UInt32[] _data2 = new UInt32[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private BooleanTwoComparisonOpTest__DataTable _dataTable; + + static BooleanTwoComparisonOpTest__TestNotZAndNotCUInt32() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (uint)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (uint)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), VectorSize); + } + + public BooleanTwoComparisonOpTest__TestNotZAndNotCUInt32() + { + 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, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (uint)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(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 BooleanTwoComparisonOpTest__DataTable(_data1, _data2, VectorSize); + } + + public bool IsSupported => Sse41.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse41.TestNotZAndNotC( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunBasicScenario_Load() + { + var result = Sse41.TestNotZAndNotC( + Sse2.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse41.TestNotZAndNotC( + Sse2.LoadAlignedVector128((UInt32*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((UInt32*)(_dataTable.inArray2Ptr)) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestNotZAndNotC), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestNotZAndNotC), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestNotZAndNotC), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((UInt32*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((UInt32*)(_dataTable.inArray2Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunClsVarScenario() + { + var result = Sse41.TestNotZAndNotC( + _clsVar1, + _clsVar2 + ); + + ValidateResult(_clsVar1, _clsVar2, result); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read>(_dataTable.inArray1Ptr); + var right = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = Sse41.TestNotZAndNotC(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)); + var result = Sse41.TestNotZAndNotC(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((UInt32*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((UInt32*)(_dataTable.inArray2Ptr)); + var result = Sse41.TestNotZAndNotC(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclFldScenario() + { + var test = new BooleanTwoComparisonOpTest__TestNotZAndNotCUInt32(); + var result = Sse41.TestNotZAndNotC(test._fld1, test._fld2); + + ValidateResult(test._fld1, test._fld2, result); + } + + public void RunFldScenario() + { + var result = Sse41.TestNotZAndNotC(_fld1, _fld2); + + ValidateResult(_fld1, _fld2, result); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128 left, Vector128 right, bool result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + + ValidateResult(inArray1, inArray2, result, method); + } + + private void ValidateResult(void* left, void* right, bool result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + + ValidateResult(inArray1, inArray2, result, method); + } + + private void ValidateResult(UInt32[] left, UInt32[] right, bool result, [CallerMemberName] string method = "") + { + var expectedResult1 = true; + + for (var i = 0; i < Op1ElementCount; i++) + { + expectedResult1 &= (((left[i] & right[i]) == 0)); + } + + var expectedResult2 = true; + + for (var i = 0; i < Op1ElementCount; i++) + { + expectedResult2 &= (((~left[i] & right[i]) == 0)); + } + + if (((expectedResult1 == false) && (expectedResult2 == false)) != result) + { + Succeeded = false; + + Console.WriteLine($"{nameof(Sse41)}.{nameof(Sse41.TestNotZAndNotC)}(Vector128, Vector128): {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/Sse41/TestNotZAndNotC.UInt64.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestNotZAndNotC.UInt64.cs new file mode 100644 index 000000000000..41935ffbc5da --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestNotZAndNotC.UInt64.cs @@ -0,0 +1,313 @@ +// 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 TestNotZAndNotCUInt64() + { + var test = new BooleanTwoComparisonOpTest__TestNotZAndNotCUInt64(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Sse2.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 (Sse2.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 (Sse2.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 BooleanTwoComparisonOpTest__TestNotZAndNotCUInt64 + { + private const int VectorSize = 16; + + private const int Op1ElementCount = VectorSize / sizeof(UInt64); + private const int Op2ElementCount = VectorSize / sizeof(UInt64); + + private static UInt64[] _data1 = new UInt64[Op1ElementCount]; + private static UInt64[] _data2 = new UInt64[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private BooleanTwoComparisonOpTest__DataTable _dataTable; + + static BooleanTwoComparisonOpTest__TestNotZAndNotCUInt64() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (ulong)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (ulong)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), VectorSize); + } + + public BooleanTwoComparisonOpTest__TestNotZAndNotCUInt64() + { + 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, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (ulong)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(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 BooleanTwoComparisonOpTest__DataTable(_data1, _data2, VectorSize); + } + + public bool IsSupported => Sse41.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse41.TestNotZAndNotC( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunBasicScenario_Load() + { + var result = Sse41.TestNotZAndNotC( + Sse2.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((UInt64*)(_dataTable.inArray2Ptr)) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse41.TestNotZAndNotC( + Sse2.LoadAlignedVector128((UInt64*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((UInt64*)(_dataTable.inArray2Ptr)) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestNotZAndNotC), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestNotZAndNotC), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((UInt64*)(_dataTable.inArray2Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestNotZAndNotC), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((UInt64*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((UInt64*)(_dataTable.inArray2Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunClsVarScenario() + { + var result = Sse41.TestNotZAndNotC( + _clsVar1, + _clsVar2 + ); + + ValidateResult(_clsVar1, _clsVar2, result); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read>(_dataTable.inArray1Ptr); + var right = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = Sse41.TestNotZAndNotC(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((UInt64*)(_dataTable.inArray2Ptr)); + var result = Sse41.TestNotZAndNotC(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((UInt64*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((UInt64*)(_dataTable.inArray2Ptr)); + var result = Sse41.TestNotZAndNotC(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclFldScenario() + { + var test = new BooleanTwoComparisonOpTest__TestNotZAndNotCUInt64(); + var result = Sse41.TestNotZAndNotC(test._fld1, test._fld2); + + ValidateResult(test._fld1, test._fld2, result); + } + + public void RunFldScenario() + { + var result = Sse41.TestNotZAndNotC(_fld1, _fld2); + + ValidateResult(_fld1, _fld2, result); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128 left, Vector128 right, bool result, [CallerMemberName] string method = "") + { + UInt64[] inArray1 = new UInt64[Op1ElementCount]; + UInt64[] inArray2 = new UInt64[Op2ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + + ValidateResult(inArray1, inArray2, result, method); + } + + private void ValidateResult(void* left, void* right, bool result, [CallerMemberName] string method = "") + { + UInt64[] inArray1 = new UInt64[Op1ElementCount]; + UInt64[] inArray2 = new UInt64[Op2ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + + ValidateResult(inArray1, inArray2, result, method); + } + + private void ValidateResult(UInt64[] left, UInt64[] right, bool result, [CallerMemberName] string method = "") + { + var expectedResult1 = true; + + for (var i = 0; i < Op1ElementCount; i++) + { + expectedResult1 &= (((left[i] & right[i]) == 0)); + } + + var expectedResult2 = true; + + for (var i = 0; i < Op1ElementCount; i++) + { + expectedResult2 &= (((~left[i] & right[i]) == 0)); + } + + if (((expectedResult1 == false) && (expectedResult2 == false)) != result) + { + Succeeded = false; + + Console.WriteLine($"{nameof(Sse41)}.{nameof(Sse41.TestNotZAndNotC)}(Vector128, Vector128): {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/Sse41/TestZ.Byte.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestZ.Byte.cs new file mode 100644 index 000000000000..c5c8f43bbca9 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestZ.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 TestZByte() + { + var test = new BooleanBinaryOpTest__TestZByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Sse2.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 (Sse2.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 (Sse2.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 BooleanBinaryOpTest__TestZByte + { + private const int VectorSize = 16; + + private const int Op1ElementCount = VectorSize / sizeof(Byte); + private const int Op2ElementCount = VectorSize / sizeof(Byte); + + private static Byte[] _data1 = new Byte[Op1ElementCount]; + private static Byte[] _data2 = new Byte[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private BooleanBinaryOpTest__DataTable _dataTable; + + static BooleanBinaryOpTest__TestZByte() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (byte)(random.Next(0, byte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (byte)(random.Next(0, byte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), VectorSize); + } + + public BooleanBinaryOpTest__TestZByte() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (byte)(random.Next(0, byte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (byte)(random.Next(0, byte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), VectorSize); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (byte)(random.Next(0, byte.MaxValue)); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (byte)(random.Next(0, byte.MaxValue)); } + _dataTable = new BooleanBinaryOpTest__DataTable(_data1, _data2, VectorSize); + } + + public bool IsSupported => Sse41.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse41.TestZ( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunBasicScenario_Load() + { + var result = Sse41.TestZ( + Sse2.LoadVector128((Byte*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Byte*)(_dataTable.inArray2Ptr)) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse41.TestZ( + Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray2Ptr)) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestZ), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestZ), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Byte*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Byte*)(_dataTable.inArray2Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestZ), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray2Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunClsVarScenario() + { + var result = Sse41.TestZ( + _clsVar1, + _clsVar2 + ); + + ValidateResult(_clsVar1, _clsVar2, result); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read>(_dataTable.inArray1Ptr); + var right = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = Sse41.TestZ(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((Byte*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((Byte*)(_dataTable.inArray2Ptr)); + var result = Sse41.TestZ(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray2Ptr)); + var result = Sse41.TestZ(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclFldScenario() + { + var test = new BooleanBinaryOpTest__TestZByte(); + var result = Sse41.TestZ(test._fld1, test._fld2); + + ValidateResult(test._fld1, test._fld2, result); + } + + public void RunFldScenario() + { + var result = Sse41.TestZ(_fld1, _fld2); + + ValidateResult(_fld1, _fld2, result); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128 left, Vector128 right, bool result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + Byte[] inArray2 = new Byte[Op2ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + + ValidateResult(inArray1, inArray2, result, method); + } + + private void ValidateResult(void* left, void* right, bool result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + Byte[] inArray2 = new Byte[Op2ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + + ValidateResult(inArray1, inArray2, result, method); + } + + private void ValidateResult(Byte[] left, Byte[] right, bool result, [CallerMemberName] string method = "") + { + var expectedResult = true; + + for (var i = 0; i < Op1ElementCount; i++) + { + expectedResult &= ((left[i] & right[i]) == 0); + } + + if (expectedResult != result) + { + Succeeded = false; + + Console.WriteLine($"{nameof(Sse41)}.{nameof(Sse41.TestZ)}(Vector128, Vector128): {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/Sse41/TestZ.Int16.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestZ.Int16.cs new file mode 100644 index 000000000000..779e3f4d9ba9 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestZ.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 TestZInt16() + { + var test = new BooleanBinaryOpTest__TestZInt16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Sse2.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 (Sse2.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 (Sse2.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 BooleanBinaryOpTest__TestZInt16 + { + private const int VectorSize = 16; + + private const int Op1ElementCount = VectorSize / sizeof(Int16); + private const int Op2ElementCount = VectorSize / sizeof(Int16); + + private static Int16[] _data1 = new Int16[Op1ElementCount]; + private static Int16[] _data2 = new Int16[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private BooleanBinaryOpTest__DataTable _dataTable; + + static BooleanBinaryOpTest__TestZInt16() + { + 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, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (short)(random.Next(short.MinValue, short.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), VectorSize); + } + + public BooleanBinaryOpTest__TestZInt16() + { + 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, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (short)(random.Next(short.MinValue, short.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), VectorSize); + + 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 BooleanBinaryOpTest__DataTable(_data1, _data2, VectorSize); + } + + public bool IsSupported => Sse41.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse41.TestZ( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunBasicScenario_Load() + { + var result = Sse41.TestZ( + Sse2.LoadVector128((Int16*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Int16*)(_dataTable.inArray2Ptr)) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse41.TestZ( + Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray2Ptr)) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestZ), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestZ), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Int16*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Int16*)(_dataTable.inArray2Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestZ), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray2Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunClsVarScenario() + { + var result = Sse41.TestZ( + _clsVar1, + _clsVar2 + ); + + ValidateResult(_clsVar1, _clsVar2, result); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read>(_dataTable.inArray1Ptr); + var right = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = Sse41.TestZ(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((Int16*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((Int16*)(_dataTable.inArray2Ptr)); + var result = Sse41.TestZ(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray2Ptr)); + var result = Sse41.TestZ(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclFldScenario() + { + var test = new BooleanBinaryOpTest__TestZInt16(); + var result = Sse41.TestZ(test._fld1, test._fld2); + + ValidateResult(test._fld1, test._fld2, result); + } + + public void RunFldScenario() + { + var result = Sse41.TestZ(_fld1, _fld2); + + ValidateResult(_fld1, _fld2, result); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128 left, Vector128 right, bool result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + + ValidateResult(inArray1, inArray2, result, method); + } + + private void ValidateResult(void* left, void* right, bool result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + + ValidateResult(inArray1, inArray2, result, method); + } + + private void ValidateResult(Int16[] left, Int16[] right, bool result, [CallerMemberName] string method = "") + { + var expectedResult = true; + + for (var i = 0; i < Op1ElementCount; i++) + { + expectedResult &= ((left[i] & right[i]) == 0); + } + + if (expectedResult != result) + { + Succeeded = false; + + Console.WriteLine($"{nameof(Sse41)}.{nameof(Sse41.TestZ)}(Vector128, Vector128): {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/Sse41/TestZ.Int32.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestZ.Int32.cs new file mode 100644 index 000000000000..2a81fd74979d --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestZ.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 TestZInt32() + { + var test = new BooleanBinaryOpTest__TestZInt32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Sse2.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 (Sse2.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 (Sse2.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 BooleanBinaryOpTest__TestZInt32 + { + private const int VectorSize = 16; + + private const int Op1ElementCount = VectorSize / sizeof(Int32); + private const int Op2ElementCount = VectorSize / sizeof(Int32); + + private static Int32[] _data1 = new Int32[Op1ElementCount]; + private static Int32[] _data2 = new Int32[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private BooleanBinaryOpTest__DataTable _dataTable; + + static BooleanBinaryOpTest__TestZInt32() + { + 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, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (int)(random.Next(int.MinValue, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), VectorSize); + } + + public BooleanBinaryOpTest__TestZInt32() + { + 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, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (int)(random.Next(int.MinValue, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), VectorSize); + + 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 BooleanBinaryOpTest__DataTable(_data1, _data2, VectorSize); + } + + public bool IsSupported => Sse41.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse41.TestZ( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunBasicScenario_Load() + { + var result = Sse41.TestZ( + Sse2.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Int32*)(_dataTable.inArray2Ptr)) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse41.TestZ( + Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray2Ptr)) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestZ), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestZ), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Int32*)(_dataTable.inArray2Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestZ), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray2Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunClsVarScenario() + { + var result = Sse41.TestZ( + _clsVar1, + _clsVar2 + ); + + ValidateResult(_clsVar1, _clsVar2, result); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read>(_dataTable.inArray1Ptr); + var right = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = Sse41.TestZ(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((Int32*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((Int32*)(_dataTable.inArray2Ptr)); + var result = Sse41.TestZ(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray2Ptr)); + var result = Sse41.TestZ(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclFldScenario() + { + var test = new BooleanBinaryOpTest__TestZInt32(); + var result = Sse41.TestZ(test._fld1, test._fld2); + + ValidateResult(test._fld1, test._fld2, result); + } + + public void RunFldScenario() + { + var result = Sse41.TestZ(_fld1, _fld2); + + ValidateResult(_fld1, _fld2, result); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128 left, Vector128 right, bool result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + + ValidateResult(inArray1, inArray2, result, method); + } + + private void ValidateResult(void* left, void* right, bool result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + + ValidateResult(inArray1, inArray2, result, method); + } + + private void ValidateResult(Int32[] left, Int32[] right, bool result, [CallerMemberName] string method = "") + { + var expectedResult = true; + + for (var i = 0; i < Op1ElementCount; i++) + { + expectedResult &= ((left[i] & right[i]) == 0); + } + + if (expectedResult != result) + { + Succeeded = false; + + Console.WriteLine($"{nameof(Sse41)}.{nameof(Sse41.TestZ)}(Vector128, Vector128): {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/Sse41/TestZ.Int64.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestZ.Int64.cs new file mode 100644 index 000000000000..61dea9900106 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestZ.Int64.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 TestZInt64() + { + var test = new BooleanBinaryOpTest__TestZInt64(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Sse2.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 (Sse2.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 (Sse2.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 BooleanBinaryOpTest__TestZInt64 + { + private const int VectorSize = 16; + + private const int Op1ElementCount = VectorSize / sizeof(Int64); + private const int Op2ElementCount = VectorSize / sizeof(Int64); + + private static Int64[] _data1 = new Int64[Op1ElementCount]; + private static Int64[] _data2 = new Int64[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private BooleanBinaryOpTest__DataTable _dataTable; + + static BooleanBinaryOpTest__TestZInt64() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (long)(random.Next(int.MinValue, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (long)(random.Next(int.MinValue, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), VectorSize); + } + + public BooleanBinaryOpTest__TestZInt64() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (long)(random.Next(int.MinValue, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (long)(random.Next(int.MinValue, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), VectorSize); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (long)(random.Next(int.MinValue, int.MaxValue)); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (long)(random.Next(int.MinValue, int.MaxValue)); } + _dataTable = new BooleanBinaryOpTest__DataTable(_data1, _data2, VectorSize); + } + + public bool IsSupported => Sse41.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse41.TestZ( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunBasicScenario_Load() + { + var result = Sse41.TestZ( + Sse2.LoadVector128((Int64*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Int64*)(_dataTable.inArray2Ptr)) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse41.TestZ( + Sse2.LoadAlignedVector128((Int64*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Int64*)(_dataTable.inArray2Ptr)) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestZ), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestZ), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Int64*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Int64*)(_dataTable.inArray2Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestZ), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Int64*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Int64*)(_dataTable.inArray2Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunClsVarScenario() + { + var result = Sse41.TestZ( + _clsVar1, + _clsVar2 + ); + + ValidateResult(_clsVar1, _clsVar2, result); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read>(_dataTable.inArray1Ptr); + var right = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = Sse41.TestZ(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((Int64*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((Int64*)(_dataTable.inArray2Ptr)); + var result = Sse41.TestZ(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((Int64*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((Int64*)(_dataTable.inArray2Ptr)); + var result = Sse41.TestZ(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclFldScenario() + { + var test = new BooleanBinaryOpTest__TestZInt64(); + var result = Sse41.TestZ(test._fld1, test._fld2); + + ValidateResult(test._fld1, test._fld2, result); + } + + public void RunFldScenario() + { + var result = Sse41.TestZ(_fld1, _fld2); + + ValidateResult(_fld1, _fld2, result); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128 left, Vector128 right, bool result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + + ValidateResult(inArray1, inArray2, result, method); + } + + private void ValidateResult(void* left, void* right, bool result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + + ValidateResult(inArray1, inArray2, result, method); + } + + private void ValidateResult(Int64[] left, Int64[] right, bool result, [CallerMemberName] string method = "") + { + var expectedResult = true; + + for (var i = 0; i < Op1ElementCount; i++) + { + expectedResult &= ((left[i] & right[i]) == 0); + } + + if (expectedResult != result) + { + Succeeded = false; + + Console.WriteLine($"{nameof(Sse41)}.{nameof(Sse41.TestZ)}(Vector128, Vector128): {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/Sse41/TestZ.SByte.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestZ.SByte.cs new file mode 100644 index 000000000000..4eb54e5784e1 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestZ.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 TestZSByte() + { + var test = new BooleanBinaryOpTest__TestZSByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Sse2.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 (Sse2.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 (Sse2.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 BooleanBinaryOpTest__TestZSByte + { + private const int VectorSize = 16; + + private const int Op1ElementCount = VectorSize / sizeof(SByte); + private const int Op2ElementCount = VectorSize / sizeof(SByte); + + private static SByte[] _data1 = new SByte[Op1ElementCount]; + private static SByte[] _data2 = new SByte[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private BooleanBinaryOpTest__DataTable _dataTable; + + static BooleanBinaryOpTest__TestZSByte() + { + 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, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), VectorSize); + } + + public BooleanBinaryOpTest__TestZSByte() + { + 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, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), VectorSize); + + 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 BooleanBinaryOpTest__DataTable(_data1, _data2, VectorSize); + } + + public bool IsSupported => Sse41.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse41.TestZ( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunBasicScenario_Load() + { + var result = Sse41.TestZ( + Sse2.LoadVector128((SByte*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((SByte*)(_dataTable.inArray2Ptr)) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse41.TestZ( + Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArray2Ptr)) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestZ), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestZ), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((SByte*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((SByte*)(_dataTable.inArray2Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestZ), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArray2Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunClsVarScenario() + { + var result = Sse41.TestZ( + _clsVar1, + _clsVar2 + ); + + ValidateResult(_clsVar1, _clsVar2, result); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read>(_dataTable.inArray1Ptr); + var right = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = Sse41.TestZ(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((SByte*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((SByte*)(_dataTable.inArray2Ptr)); + var result = Sse41.TestZ(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArray2Ptr)); + var result = Sse41.TestZ(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclFldScenario() + { + var test = new BooleanBinaryOpTest__TestZSByte(); + var result = Sse41.TestZ(test._fld1, test._fld2); + + ValidateResult(test._fld1, test._fld2, result); + } + + public void RunFldScenario() + { + var result = Sse41.TestZ(_fld1, _fld2); + + ValidateResult(_fld1, _fld2, result); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128 left, Vector128 right, bool result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + + ValidateResult(inArray1, inArray2, result, method); + } + + private void ValidateResult(void* left, void* right, bool result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + + ValidateResult(inArray1, inArray2, result, method); + } + + private void ValidateResult(SByte[] left, SByte[] right, bool result, [CallerMemberName] string method = "") + { + var expectedResult = true; + + for (var i = 0; i < Op1ElementCount; i++) + { + expectedResult &= ((left[i] & right[i]) == 0); + } + + if (expectedResult != result) + { + Succeeded = false; + + Console.WriteLine($"{nameof(Sse41)}.{nameof(Sse41.TestZ)}(Vector128, Vector128): {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/Sse41/TestZ.UInt16.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestZ.UInt16.cs new file mode 100644 index 000000000000..39319c29fbd3 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestZ.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 TestZUInt16() + { + var test = new BooleanBinaryOpTest__TestZUInt16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Sse2.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 (Sse2.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 (Sse2.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 BooleanBinaryOpTest__TestZUInt16 + { + private const int VectorSize = 16; + + private const int Op1ElementCount = VectorSize / sizeof(UInt16); + private const int Op2ElementCount = VectorSize / sizeof(UInt16); + + private static UInt16[] _data1 = new UInt16[Op1ElementCount]; + private static UInt16[] _data2 = new UInt16[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private BooleanBinaryOpTest__DataTable _dataTable; + + static BooleanBinaryOpTest__TestZUInt16() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (ushort)(random.Next(0, ushort.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (ushort)(random.Next(0, ushort.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), VectorSize); + } + + public BooleanBinaryOpTest__TestZUInt16() + { + 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, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (ushort)(random.Next(0, ushort.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), VectorSize); + + 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 BooleanBinaryOpTest__DataTable(_data1, _data2, VectorSize); + } + + public bool IsSupported => Sse41.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse41.TestZ( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunBasicScenario_Load() + { + var result = Sse41.TestZ( + Sse2.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse41.TestZ( + Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArray2Ptr)) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestZ), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestZ), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestZ), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArray2Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunClsVarScenario() + { + var result = Sse41.TestZ( + _clsVar1, + _clsVar2 + ); + + ValidateResult(_clsVar1, _clsVar2, result); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read>(_dataTable.inArray1Ptr); + var right = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = Sse41.TestZ(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)); + var result = Sse41.TestZ(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArray2Ptr)); + var result = Sse41.TestZ(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclFldScenario() + { + var test = new BooleanBinaryOpTest__TestZUInt16(); + var result = Sse41.TestZ(test._fld1, test._fld2); + + ValidateResult(test._fld1, test._fld2, result); + } + + public void RunFldScenario() + { + var result = Sse41.TestZ(_fld1, _fld2); + + ValidateResult(_fld1, _fld2, result); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128 left, Vector128 right, bool result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + + ValidateResult(inArray1, inArray2, result, method); + } + + private void ValidateResult(void* left, void* right, bool result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + + ValidateResult(inArray1, inArray2, result, method); + } + + private void ValidateResult(UInt16[] left, UInt16[] right, bool result, [CallerMemberName] string method = "") + { + var expectedResult = true; + + for (var i = 0; i < Op1ElementCount; i++) + { + expectedResult &= ((left[i] & right[i]) == 0); + } + + if (expectedResult != result) + { + Succeeded = false; + + Console.WriteLine($"{nameof(Sse41)}.{nameof(Sse41.TestZ)}(Vector128, Vector128): {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/Sse41/TestZ.UInt32.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestZ.UInt32.cs new file mode 100644 index 000000000000..f40495f54154 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestZ.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 TestZUInt32() + { + var test = new BooleanBinaryOpTest__TestZUInt32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Sse2.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 (Sse2.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 (Sse2.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 BooleanBinaryOpTest__TestZUInt32 + { + private const int VectorSize = 16; + + private const int Op1ElementCount = VectorSize / sizeof(UInt32); + private const int Op2ElementCount = VectorSize / sizeof(UInt32); + + private static UInt32[] _data1 = new UInt32[Op1ElementCount]; + private static UInt32[] _data2 = new UInt32[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private BooleanBinaryOpTest__DataTable _dataTable; + + static BooleanBinaryOpTest__TestZUInt32() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (uint)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (uint)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), VectorSize); + } + + public BooleanBinaryOpTest__TestZUInt32() + { + 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, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (uint)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(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 BooleanBinaryOpTest__DataTable(_data1, _data2, VectorSize); + } + + public bool IsSupported => Sse41.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse41.TestZ( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunBasicScenario_Load() + { + var result = Sse41.TestZ( + Sse2.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse41.TestZ( + Sse2.LoadAlignedVector128((UInt32*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((UInt32*)(_dataTable.inArray2Ptr)) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestZ), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestZ), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestZ), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((UInt32*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((UInt32*)(_dataTable.inArray2Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunClsVarScenario() + { + var result = Sse41.TestZ( + _clsVar1, + _clsVar2 + ); + + ValidateResult(_clsVar1, _clsVar2, result); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read>(_dataTable.inArray1Ptr); + var right = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = Sse41.TestZ(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)); + var result = Sse41.TestZ(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((UInt32*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((UInt32*)(_dataTable.inArray2Ptr)); + var result = Sse41.TestZ(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclFldScenario() + { + var test = new BooleanBinaryOpTest__TestZUInt32(); + var result = Sse41.TestZ(test._fld1, test._fld2); + + ValidateResult(test._fld1, test._fld2, result); + } + + public void RunFldScenario() + { + var result = Sse41.TestZ(_fld1, _fld2); + + ValidateResult(_fld1, _fld2, result); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128 left, Vector128 right, bool result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + + ValidateResult(inArray1, inArray2, result, method); + } + + private void ValidateResult(void* left, void* right, bool result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + + ValidateResult(inArray1, inArray2, result, method); + } + + private void ValidateResult(UInt32[] left, UInt32[] right, bool result, [CallerMemberName] string method = "") + { + var expectedResult = true; + + for (var i = 0; i < Op1ElementCount; i++) + { + expectedResult &= ((left[i] & right[i]) == 0); + } + + if (expectedResult != result) + { + Succeeded = false; + + Console.WriteLine($"{nameof(Sse41)}.{nameof(Sse41.TestZ)}(Vector128, Vector128): {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/Sse41/TestZ.UInt64.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestZ.UInt64.cs new file mode 100644 index 000000000000..e71b9f7c68dd --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/TestZ.UInt64.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 TestZUInt64() + { + var test = new BooleanBinaryOpTest__TestZUInt64(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Sse2.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 (Sse2.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 (Sse2.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 BooleanBinaryOpTest__TestZUInt64 + { + private const int VectorSize = 16; + + private const int Op1ElementCount = VectorSize / sizeof(UInt64); + private const int Op2ElementCount = VectorSize / sizeof(UInt64); + + private static UInt64[] _data1 = new UInt64[Op1ElementCount]; + private static UInt64[] _data2 = new UInt64[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private BooleanBinaryOpTest__DataTable _dataTable; + + static BooleanBinaryOpTest__TestZUInt64() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (ulong)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (ulong)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), VectorSize); + } + + public BooleanBinaryOpTest__TestZUInt64() + { + 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, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (ulong)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(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 BooleanBinaryOpTest__DataTable(_data1, _data2, VectorSize); + } + + public bool IsSupported => Sse41.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse41.TestZ( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunBasicScenario_Load() + { + var result = Sse41.TestZ( + Sse2.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((UInt64*)(_dataTable.inArray2Ptr)) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse41.TestZ( + Sse2.LoadAlignedVector128((UInt64*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((UInt64*)(_dataTable.inArray2Ptr)) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestZ), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestZ), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((UInt64*)(_dataTable.inArray2Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse41).GetMethod(nameof(Sse41.TestZ), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((UInt64*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((UInt64*)(_dataTable.inArray2Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunClsVarScenario() + { + var result = Sse41.TestZ( + _clsVar1, + _clsVar2 + ); + + ValidateResult(_clsVar1, _clsVar2, result); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read>(_dataTable.inArray1Ptr); + var right = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = Sse41.TestZ(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((UInt64*)(_dataTable.inArray2Ptr)); + var result = Sse41.TestZ(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((UInt64*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((UInt64*)(_dataTable.inArray2Ptr)); + var result = Sse41.TestZ(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclFldScenario() + { + var test = new BooleanBinaryOpTest__TestZUInt64(); + var result = Sse41.TestZ(test._fld1, test._fld2); + + ValidateResult(test._fld1, test._fld2, result); + } + + public void RunFldScenario() + { + var result = Sse41.TestZ(_fld1, _fld2); + + ValidateResult(_fld1, _fld2, result); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128 left, Vector128 right, bool result, [CallerMemberName] string method = "") + { + UInt64[] inArray1 = new UInt64[Op1ElementCount]; + UInt64[] inArray2 = new UInt64[Op2ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + + ValidateResult(inArray1, inArray2, result, method); + } + + private void ValidateResult(void* left, void* right, bool result, [CallerMemberName] string method = "") + { + UInt64[] inArray1 = new UInt64[Op1ElementCount]; + UInt64[] inArray2 = new UInt64[Op2ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + + ValidateResult(inArray1, inArray2, result, method); + } + + private void ValidateResult(UInt64[] left, UInt64[] right, bool result, [CallerMemberName] string method = "") + { + var expectedResult = true; + + for (var i = 0; i < Op1ElementCount; i++) + { + expectedResult &= ((left[i] & right[i]) == 0); + } + + if (expectedResult != result) + { + Succeeded = false; + + Console.WriteLine($"{nameof(Sse41)}.{nameof(Sse41.TestZ)}(Vector128, Vector128): {method} failed:"); + Console.WriteLine($" left: ({string.Join(", ", left)})"); + Console.WriteLine($" right: ({string.Join(", ", right)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} From ed361f0db656289216978a7b3e7c956eb61f81f5 Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Tue, 27 Feb 2018 07:45:35 -0800 Subject: [PATCH 3/3] Adding some asserts that we won't overwrite one of the hwintrinsic operand registers. --- src/jit/emitxarch.cpp | 14 ++ src/jit/hwintrinsiclistxarch.h | 244 ++++++++++++++++----------------- src/jit/lsraxarch.cpp | 41 +++++- src/jit/namedintrinsiclist.h | 4 + 4 files changed, 175 insertions(+), 128 deletions(-) diff --git a/src/jit/emitxarch.cpp b/src/jit/emitxarch.cpp index 2753c2dc8192..64a76357c104 100644 --- a/src/jit/emitxarch.cpp +++ b/src/jit/emitxarch.cpp @@ -5490,6 +5490,9 @@ void emitter::emitIns_SIMD_R_R_R(instruction ins, emitAttr attr, regNumber reg, { if (reg1 != reg) { + // Ensure we aren't overwriting op2 + assert(reg2 != reg); + emitIns_R_R(INS_movaps, attr, reg, reg1); } emitIns_R_R(ins, attr, reg, reg2); @@ -5569,10 +5572,18 @@ void emitter::emitIns_SIMD_R_R_R_R( // SSE4.1 blendv* hardcode the mask vector (op3) in XMM0 if (reg3 != REG_XMM0) { + // Ensure we aren't overwriting op1 or op2 + assert(reg1 != REG_XMM0); + assert(reg2 != REG_XMM0); + emitIns_R_R(INS_movaps, attr, REG_XMM0, reg3); } if (reg1 != reg) { + // Ensure we aren't overwriting op2 or op3 + assert(reg2 != reg); + assert((reg3 == REG_XMM0) || (reg != REG_XMM0)); + emitIns_R_R(INS_movaps, attr, reg, reg1); } emitIns_R_R(ins, attr, reg, reg2); @@ -5657,6 +5668,9 @@ void emitter::emitIns_SIMD_R_R_R_I( { if (reg1 != reg) { + // Ensure we aren't overwriting op2 + assert(reg2 != reg); + emitIns_R_R(INS_movaps, attr, reg, reg1); } emitIns_R_R_I(ins, attr, reg, reg2, ival); diff --git a/src/jit/hwintrinsiclistxarch.h b/src/jit/hwintrinsiclistxarch.h index be9d0311360b..cc4710a8e615 100644 --- a/src/jit/hwintrinsiclistxarch.h +++ b/src/jit/hwintrinsiclistxarch.h @@ -33,29 +33,29 @@ HARDWARE_INTRINSIC(SSE_AddScalar, "AddScalar" HARDWARE_INTRINSIC(SSE_And, "And", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_andps, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_Commutative) HARDWARE_INTRINSIC(SSE_AndNot, "AndNot", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_andnps, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) HARDWARE_INTRINSIC(SSE_CompareEqual, "CompareEqual", SSE, 0, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpps, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_Commutative) -HARDWARE_INTRINSIC(SSE_CompareEqualOrderedScalar, "CompareEqualOrderedScalar", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_comiss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_MultiIns|HW_Flag_NoContainment) +HARDWARE_INTRINSIC(SSE_CompareEqualOrderedScalar, "CompareEqualOrderedScalar", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_comiss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_MultiIns|HW_Flag_NoContainment|HW_Flag_NoRMWSemantics) HARDWARE_INTRINSIC(SSE_CompareEqualScalar, "CompareEqualScalar", SSE, 0, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) -HARDWARE_INTRINSIC(SSE_CompareEqualUnorderedScalar, "CompareEqualUnorderedScalar", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_ucomiss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_MultiIns|HW_Flag_NoContainment) +HARDWARE_INTRINSIC(SSE_CompareEqualUnorderedScalar, "CompareEqualUnorderedScalar", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_ucomiss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_MultiIns|HW_Flag_NoContainment|HW_Flag_NoRMWSemantics) HARDWARE_INTRINSIC(SSE_CompareGreaterThan, "CompareGreaterThan", SSE, 6, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpps, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(SSE_CompareGreaterThanOrderedScalar, "CompareGreaterThanOrderedScalar", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_comiss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_MultiIns|HW_Flag_NoContainment) +HARDWARE_INTRINSIC(SSE_CompareGreaterThanOrderedScalar, "CompareGreaterThanOrderedScalar", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_comiss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_MultiIns|HW_Flag_NoContainment|HW_Flag_NoRMWSemantics) HARDWARE_INTRINSIC(SSE_CompareGreaterThanScalar, "CompareGreaterThanScalar", SSE, 6, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) -HARDWARE_INTRINSIC(SSE_CompareGreaterThanUnorderedScalar, "CompareGreaterThanUnorderedScalar", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_ucomiss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_MultiIns|HW_Flag_NoContainment) +HARDWARE_INTRINSIC(SSE_CompareGreaterThanUnorderedScalar, "CompareGreaterThanUnorderedScalar", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_ucomiss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_MultiIns|HW_Flag_NoContainment|HW_Flag_NoRMWSemantics) HARDWARE_INTRINSIC(SSE_CompareGreaterThanOrEqual, "CompareGreaterThanOrEqual", SSE, 5, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpps, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(SSE_CompareGreaterThanOrEqualOrderedScalar, "CompareGreaterThanOrEqualOrderedScalar", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_comiss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_MultiIns|HW_Flag_NoContainment) +HARDWARE_INTRINSIC(SSE_CompareGreaterThanOrEqualOrderedScalar, "CompareGreaterThanOrEqualOrderedScalar", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_comiss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_MultiIns|HW_Flag_NoContainment|HW_Flag_NoRMWSemantics) HARDWARE_INTRINSIC(SSE_CompareGreaterThanOrEqualScalar, "CompareGreaterThanOrEqualScalar", SSE, 5, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) -HARDWARE_INTRINSIC(SSE_CompareGreaterThanOrEqualUnorderedScalar, "CompareGreaterThanOrEqualUnorderedScalar", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_ucomiss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_MultiIns|HW_Flag_NoContainment) +HARDWARE_INTRINSIC(SSE_CompareGreaterThanOrEqualUnorderedScalar, "CompareGreaterThanOrEqualUnorderedScalar", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_ucomiss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_MultiIns|HW_Flag_NoContainment|HW_Flag_NoRMWSemantics) HARDWARE_INTRINSIC(SSE_CompareLessThan, "CompareLessThan", SSE, 1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpps, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(SSE_CompareLessThanOrderedScalar, "CompareLessThanOrderedScalar", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_comiss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_MultiIns|HW_Flag_NoContainment) +HARDWARE_INTRINSIC(SSE_CompareLessThanOrderedScalar, "CompareLessThanOrderedScalar", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_comiss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_MultiIns|HW_Flag_NoContainment|HW_Flag_NoRMWSemantics) HARDWARE_INTRINSIC(SSE_CompareLessThanScalar, "CompareLessThanScalar", SSE, 1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) -HARDWARE_INTRINSIC(SSE_CompareLessThanUnorderedScalar, "CompareLessThanUnorderedScalar", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_ucomiss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_MultiIns|HW_Flag_NoContainment) +HARDWARE_INTRINSIC(SSE_CompareLessThanUnorderedScalar, "CompareLessThanUnorderedScalar", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_ucomiss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_MultiIns|HW_Flag_NoContainment|HW_Flag_NoRMWSemantics) HARDWARE_INTRINSIC(SSE_CompareLessThanOrEqual, "CompareLessThanOrEqual", SSE, 2, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpps, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(SSE_CompareLessThanOrEqualOrderedScalar, "CompareLessThanOrEqualOrderedScalar", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_comiss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_MultiIns|HW_Flag_NoContainment) +HARDWARE_INTRINSIC(SSE_CompareLessThanOrEqualOrderedScalar, "CompareLessThanOrEqualOrderedScalar", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_comiss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_MultiIns|HW_Flag_NoContainment|HW_Flag_NoRMWSemantics) HARDWARE_INTRINSIC(SSE_CompareLessThanOrEqualScalar, "CompareLessThanOrEqualScalar", SSE, 2, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) -HARDWARE_INTRINSIC(SSE_CompareLessThanOrEqualUnorderedScalar, "CompareLessThanOrEqualUnorderedScalar", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_ucomiss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_MultiIns|HW_Flag_NoContainment) +HARDWARE_INTRINSIC(SSE_CompareLessThanOrEqualUnorderedScalar, "CompareLessThanOrEqualUnorderedScalar", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_ucomiss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_MultiIns|HW_Flag_NoContainment|HW_Flag_NoRMWSemantics) HARDWARE_INTRINSIC(SSE_CompareNotEqual, "CompareNotEqual", SSE, 4, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpps, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_Commutative) -HARDWARE_INTRINSIC(SSE_CompareNotEqualOrderedScalar, "CompareNotEqualOrderedScalar", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_comiss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_MultiIns|HW_Flag_NoContainment) +HARDWARE_INTRINSIC(SSE_CompareNotEqualOrderedScalar, "CompareNotEqualOrderedScalar", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_comiss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_MultiIns|HW_Flag_NoContainment|HW_Flag_NoRMWSemantics) HARDWARE_INTRINSIC(SSE_CompareNotEqualScalar, "CompareNotEqualScalar", SSE, 4, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) -HARDWARE_INTRINSIC(SSE_CompareNotEqualUnorderedScalar, "CompareNotEqualUnorderedScalar", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_ucomiss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_MultiIns|HW_Flag_NoContainment) +HARDWARE_INTRINSIC(SSE_CompareNotEqualUnorderedScalar, "CompareNotEqualUnorderedScalar", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_ucomiss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_MultiIns|HW_Flag_NoContainment|HW_Flag_NoRMWSemantics) HARDWARE_INTRINSIC(SSE_CompareNotGreaterThan, "CompareNotGreaterThan", SSE, 2, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpps, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) HARDWARE_INTRINSIC(SSE_CompareNotGreaterThanScalar, "CompareNotGreaterThanScalar", SSE, 2, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) HARDWARE_INTRINSIC(SSE_CompareNotGreaterThanOrEqual, "CompareNotGreaterThanOrEqual", SSE, 1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpps, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) @@ -68,53 +68,53 @@ HARDWARE_INTRINSIC(SSE_CompareOrdered, "CompareOrd HARDWARE_INTRINSIC(SSE_CompareOrderedScalar, "CompareOrderedScalar", SSE, 7, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) HARDWARE_INTRINSIC(SSE_CompareUnordered, "CompareUnordered", SSE, 3, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpps, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) HARDWARE_INTRINSIC(SSE_CompareUnorderedScalar, "CompareUnorderedScalar", SSE, 3, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) -HARDWARE_INTRINSIC(SSE_ConvertToInt32, "ConvertToInt32", SSE, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cvtss2si, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(SSE_ConvertToInt64, "ConvertToInt64", SSE, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cvtss2si, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(SSE_ConvertToSingle, "ConvertToSingle", SSE, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movss, INS_invalid}, HW_Category_Helper, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(SSE_ConvertScalarToVector128Single, "ConvertScalarToVector128Single", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cvtsi2ss, INS_invalid}, HW_Category_Special, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(SSE_ConvertToInt32WithTruncation, "ConvertToInt32WithTruncation", SSE, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cvttss2si, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(SSE_ConvertToInt64WithTruncation, "ConvertToInt64WithTruncation", SSE, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cvttss2si, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(SSE_ConvertToInt32, "ConvertToInt32", SSE, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cvtss2si, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE_ConvertToInt64, "ConvertToInt64", SSE, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cvtss2si, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE_ConvertToSingle, "ConvertToSingle", SSE, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movss, INS_invalid}, HW_Category_Helper, HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE_ConvertScalarToVector128Single, "ConvertScalarToVector128Single", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cvtsi2ss, INS_invalid}, HW_Category_Special, HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE_ConvertToInt32WithTruncation, "ConvertToInt32WithTruncation", SSE, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cvttss2si, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE_ConvertToInt64WithTruncation, "ConvertToInt64WithTruncation", SSE, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cvttss2si, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_NoRMWSemantics) HARDWARE_INTRINSIC(SSE_Divide, "Divide", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_divps, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) HARDWARE_INTRINSIC(SSE_DivideScalar, "DivideScalar", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_divss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) -HARDWARE_INTRINSIC(SSE_LoadAlignedVector128, "LoadAlignedVector128", SSE, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movaps, INS_invalid}, HW_Category_MemoryLoad, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(SSE_LoadHigh, "LoadHigh", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movhps, INS_invalid}, HW_Category_MemoryLoad, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(SSE_LoadLow, "LoadLow", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movlps, INS_invalid}, HW_Category_MemoryLoad, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(SSE_LoadScalarVector128, "LoadScalarVector128", SSE, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movss, INS_invalid}, HW_Category_MemoryLoad, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(SSE_LoadVector128, "LoadVector128", SSE, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movups, INS_invalid}, HW_Category_MemoryLoad, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(SSE_LoadAlignedVector128, "LoadAlignedVector128", SSE, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movaps, INS_invalid}, HW_Category_MemoryLoad, HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE_LoadHigh, "LoadHigh", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movhps, INS_invalid}, HW_Category_MemoryLoad, HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE_LoadLow, "LoadLow", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movlps, INS_invalid}, HW_Category_MemoryLoad, HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE_LoadScalarVector128, "LoadScalarVector128", SSE, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movss, INS_invalid}, HW_Category_MemoryLoad, HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE_LoadVector128, "LoadVector128", SSE, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movups, INS_invalid}, HW_Category_MemoryLoad, HW_Flag_NoRMWSemantics) HARDWARE_INTRINSIC(SSE_Max, "Max", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_maxps, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_Commutative) HARDWARE_INTRINSIC(SSE_MaxScalar, "MaxScalar", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_maxss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) HARDWARE_INTRINSIC(SSE_Min, "Min", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_minps, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_Commutative) HARDWARE_INTRINSIC(SSE_MinScalar, "MinScalar", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_minss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) HARDWARE_INTRINSIC(SSE_MoveHighToLow, "MoveHighToLow", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movhlps, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoContainment) HARDWARE_INTRINSIC(SSE_MoveLowToHigh, "MoveLowToHigh", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movlhps, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoContainment) -HARDWARE_INTRINSIC(SSE_MoveMask, "MoveMask", SSE, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movmskps, INS_invalid}, HW_Category_Special, HW_Flag_NoContainment) +HARDWARE_INTRINSIC(SSE_MoveMask, "MoveMask", SSE, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movmskps, INS_invalid}, HW_Category_Special, HW_Flag_NoContainment|HW_Flag_NoRMWSemantics) HARDWARE_INTRINSIC(SSE_MoveScalar, "MoveScalar", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_NoContainment) HARDWARE_INTRINSIC(SSE_Multiply, "Multiply", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_mulps, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_Commutative) HARDWARE_INTRINSIC(SSE_MultiplyScalar, "MultiplyScalar", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_mulss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) HARDWARE_INTRINSIC(SSE_Or, "Or", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_orps, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_Commutative) -HARDWARE_INTRINSIC(SSE_Prefetch0, "Prefetch0", SSE, -1, 0, 1, {INS_invalid, INS_prefetcht0, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Special, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(SSE_Prefetch1, "Prefetch1", SSE, -1, 0, 1, {INS_invalid, INS_prefetcht1, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Special, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(SSE_Prefetch2, "Prefetch2", SSE, -1, 0, 1, {INS_invalid, INS_prefetcht2, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Special, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(SSE_PrefetchNonTemporal, "PrefetchNonTemporal", SSE, -1, 0, 1, {INS_invalid, INS_prefetchnta, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Special, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(SSE_Reciprocal, "Reciprocal", SSE, -1, 16, 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_NoFlag) +HARDWARE_INTRINSIC(SSE_Prefetch0, "Prefetch0", SSE, -1, 0, 1, {INS_invalid, INS_prefetcht0, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Special, HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE_Prefetch1, "Prefetch1", SSE, -1, 0, 1, {INS_invalid, INS_prefetcht1, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Special, HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE_Prefetch2, "Prefetch2", SSE, -1, 0, 1, {INS_invalid, INS_prefetcht2, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Special, HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE_PrefetchNonTemporal, "PrefetchNonTemporal", SSE, -1, 0, 1, {INS_invalid, INS_prefetchnta, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Special, HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE_Reciprocal, "Reciprocal", SSE, -1, 16, 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(SSE_ReciprocalScalar, "ReciprocalScalar", SSE, -1, 16, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_rcpss, INS_invalid}, HW_Category_Special, HW_Flag_CopyUpperBits) -HARDWARE_INTRINSIC(SSE_ReciprocalSqrt, "ReciprocalSqrt", SSE, -1, 16, 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_NoFlag) +HARDWARE_INTRINSIC(SSE_ReciprocalSqrt, "ReciprocalSqrt", SSE, -1, 16, 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(SSE_ReciprocalSqrtScalar, "ReciprocalSqrtScalar", SSE, -1, 16, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_rsqrtss, INS_invalid}, HW_Category_Special, HW_Flag_CopyUpperBits) -HARDWARE_INTRINSIC(SSE_SetAllVector128, "SetAllVector128", SSE, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_NoCodeGen) -HARDWARE_INTRINSIC(SSE_SetScalarVector128, "SetScalarVector128", SSE, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movss, INS_invalid}, HW_Category_Helper, HW_Flag_MultiIns) +HARDWARE_INTRINSIC(SSE_SetAllVector128, "SetAllVector128", SSE, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_NoCodeGen|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE_SetScalarVector128, "SetScalarVector128", SSE, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movss, INS_invalid}, HW_Category_Helper, HW_Flag_MultiIns|HW_Flag_NoRMWSemantics) HARDWARE_INTRINSIC(SSE_SetVector128, "SetVector128", SSE, -1, 16, 4, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_NoCodeGen) -HARDWARE_INTRINSIC(SSE_SetZeroVector128, "SetZeroVector128", SSE, -1, 16, 0, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_xorps, INS_invalid}, HW_Category_Helper, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(SSE_SetZeroVector128, "SetZeroVector128", SSE, -1, 16, 0, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_xorps, INS_invalid}, HW_Category_Helper, HW_Flag_NoRMWSemantics) HARDWARE_INTRINSIC(SSE_Shuffle, "Shuffle", SSE, -1, 16, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_shufps, INS_invalid}, HW_Category_IMM, HW_Flag_FullRangeIMM) -HARDWARE_INTRINSIC(SSE_Sqrt, "Sqrt", SSE, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sqrtps, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(SSE_Sqrt, "Sqrt", SSE, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sqrtps, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoRMWSemantics) HARDWARE_INTRINSIC(SSE_SqrtScalar, "SqrtScalar", SSE, -1, 16, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sqrtss, INS_invalid}, HW_Category_Special, HW_Flag_CopyUpperBits) -HARDWARE_INTRINSIC(SSE_StaticCast, "StaticCast", SSE, -1, 16, 1, {INS_movaps, INS_movaps, INS_movaps, INS_movaps, INS_movaps, INS_movaps, INS_movaps, INS_movaps, INS_movaps, INS_movaps}, HW_Category_Helper, HW_Flag_TwoTypeGeneric) -HARDWARE_INTRINSIC(SSE_Store, "Store", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movups, INS_invalid}, HW_Category_MemoryStore, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(SSE_StoreAligned, "StoreAligned", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movaps, INS_invalid}, HW_Category_MemoryStore, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(SSE_StoreAlignedNonTemporal, "StoreAlignedNonTemporal", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movntps, INS_invalid}, HW_Category_MemoryStore, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(SSE_StoreFence, "StoreFence", SSE, -1, 0, 0, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Special, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(SSE_StoreHigh, "StoreHigh", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movhps, INS_invalid}, HW_Category_MemoryStore, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(SSE_StoreLow, "StoreLow", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movlps, INS_invalid}, HW_Category_MemoryStore, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(SSE_StoreScalar, "StoreScalar", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movss, INS_invalid}, HW_Category_MemoryStore, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(SSE_StaticCast, "StaticCast", SSE, -1, 16, 1, {INS_movaps, INS_movaps, INS_movaps, INS_movaps, INS_movaps, INS_movaps, INS_movaps, INS_movaps, INS_movaps, INS_movaps}, HW_Category_Helper, HW_Flag_TwoTypeGeneric|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE_Store, "Store", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movups, INS_invalid}, HW_Category_MemoryStore, HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE_StoreAligned, "StoreAligned", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movaps, INS_invalid}, HW_Category_MemoryStore, HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE_StoreAlignedNonTemporal, "StoreAlignedNonTemporal", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movntps, INS_invalid}, HW_Category_MemoryStore, HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE_StoreFence, "StoreFence", SSE, -1, 0, 0, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Special, HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE_StoreHigh, "StoreHigh", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movhps, INS_invalid}, HW_Category_MemoryStore, HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE_StoreLow, "StoreLow", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movlps, INS_invalid}, HW_Category_MemoryStore, HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE_StoreScalar, "StoreScalar", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movss, INS_invalid}, HW_Category_MemoryStore, HW_Flag_NoRMWSemantics) HARDWARE_INTRINSIC(SSE_Subtract, "Subtract", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_subps, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) HARDWARE_INTRINSIC(SSE_SubtractScalar, "SubtractScalar", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_subss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) HARDWARE_INTRINSIC(SSE_UnpackHigh, "UnpackHigh", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_unpckhps, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) @@ -134,29 +134,29 @@ HARDWARE_INTRINSIC(SSE2_And, "And", HARDWARE_INTRINSIC(SSE2_AndNot, "AndNot", SSE2, -1, 16, 2, {INS_pandn, INS_pandn, INS_pandn, INS_pandn, INS_pandn, INS_pandn, INS_pandn, INS_pandn, INS_invalid, INS_andnpd}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) HARDWARE_INTRINSIC(SSE2_Average, "Average", SSE2, -1, 16, 2, {INS_invalid, INS_pavgb, INS_invalid, INS_pavgw, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_Commutative) HARDWARE_INTRINSIC(SSE2_CompareEqual, "CompareEqual", SSE2, 0, 16, 2, {INS_pcmpeqb, INS_pcmpeqb, INS_pcmpeqw, INS_pcmpeqw, INS_pcmpeqd, INS_pcmpeqd, INS_invalid, INS_invalid, INS_invalid, INS_cmppd}, HW_Category_SimpleSIMD, HW_Flag_Commutative) -HARDWARE_INTRINSIC(SSE2_CompareEqualOrderedScalar, "CompareEqualOrderedScalar", SSE2, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_comisd}, HW_Category_SIMDScalar, HW_Flag_MultiIns|HW_Flag_NoContainment) +HARDWARE_INTRINSIC(SSE2_CompareEqualOrderedScalar, "CompareEqualOrderedScalar", SSE2, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_comisd}, HW_Category_SIMDScalar, HW_Flag_MultiIns|HW_Flag_NoContainment|HW_Flag_NoRMWSemantics) HARDWARE_INTRINSIC(SSE2_CompareEqualScalar, "CompareEqualScalar", SSE2, 0, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpsd}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) -HARDWARE_INTRINSIC(SSE2_CompareEqualUnorderedScalar, "CompareEqualUnorderedScalar", SSE2, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_ucomisd}, HW_Category_SIMDScalar, HW_Flag_MultiIns|HW_Flag_NoContainment) +HARDWARE_INTRINSIC(SSE2_CompareEqualUnorderedScalar, "CompareEqualUnorderedScalar", SSE2, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_ucomisd}, HW_Category_SIMDScalar, HW_Flag_MultiIns|HW_Flag_NoContainment|HW_Flag_NoRMWSemantics) HARDWARE_INTRINSIC(SSE2_CompareGreaterThan, "CompareGreaterThan", SSE2, 6, 16, 2, {INS_pcmpgtb, INS_invalid, INS_pcmpgtw, INS_invalid, INS_pcmpgtd, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmppd}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(SSE2_CompareGreaterThanOrderedScalar, "CompareGreaterThanOrderedScalar", SSE2, -1, 16, 2, {INS_pcmpgtb, INS_invalid, INS_pcmpgtw, INS_invalid, INS_pcmpgtd, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_comisd}, HW_Category_SIMDScalar, HW_Flag_MultiIns|HW_Flag_NoContainment) +HARDWARE_INTRINSIC(SSE2_CompareGreaterThanOrderedScalar, "CompareGreaterThanOrderedScalar", SSE2, -1, 16, 2, {INS_pcmpgtb, INS_invalid, INS_pcmpgtw, INS_invalid, INS_pcmpgtd, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_comisd}, HW_Category_SIMDScalar, HW_Flag_MultiIns|HW_Flag_NoContainment|HW_Flag_NoRMWSemantics) HARDWARE_INTRINSIC(SSE2_CompareGreaterThanScalar, "CompareGreaterThanScalar", SSE2, 6, 16, 2, {INS_pcmpgtb, INS_invalid, INS_pcmpgtw, INS_invalid, INS_pcmpgtd, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpsd}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) -HARDWARE_INTRINSIC(SSE2_CompareGreaterThanUnorderedScalar, "CompareGreaterThanUnorderedScalar", SSE2, -1, 16, 2, {INS_pcmpgtb, INS_invalid, INS_pcmpgtw, INS_invalid, INS_pcmpgtd, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_ucomisd}, HW_Category_SIMDScalar, HW_Flag_MultiIns|HW_Flag_NoContainment) +HARDWARE_INTRINSIC(SSE2_CompareGreaterThanUnorderedScalar, "CompareGreaterThanUnorderedScalar", SSE2, -1, 16, 2, {INS_pcmpgtb, INS_invalid, INS_pcmpgtw, INS_invalid, INS_pcmpgtd, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_ucomisd}, HW_Category_SIMDScalar, HW_Flag_MultiIns|HW_Flag_NoContainment|HW_Flag_NoRMWSemantics) HARDWARE_INTRINSIC(SSE2_CompareGreaterThanOrEqual, "CompareGreaterThanOrEqual", SSE2, 5, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmppd}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(SSE2_CompareGreaterThanOrEqualOrderedScalar, "CompareGreaterThanOrEqualOrderedScalar", SSE2, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_comisd}, HW_Category_SIMDScalar, HW_Flag_MultiIns|HW_Flag_NoContainment) +HARDWARE_INTRINSIC(SSE2_CompareGreaterThanOrEqualOrderedScalar, "CompareGreaterThanOrEqualOrderedScalar", SSE2, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_comisd}, HW_Category_SIMDScalar, HW_Flag_MultiIns|HW_Flag_NoContainment|HW_Flag_NoRMWSemantics) HARDWARE_INTRINSIC(SSE2_CompareGreaterThanOrEqualScalar, "CompareGreaterThanOrEqualScalar", SSE2, 5, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpsd}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) -HARDWARE_INTRINSIC(SSE2_CompareGreaterThanOrEqualUnorderedScalar, "CompareGreaterThanOrEqualUnorderedScalar", SSE2, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_ucomisd}, HW_Category_SIMDScalar, HW_Flag_MultiIns|HW_Flag_NoContainment) +HARDWARE_INTRINSIC(SSE2_CompareGreaterThanOrEqualUnorderedScalar, "CompareGreaterThanOrEqualUnorderedScalar", SSE2, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_ucomisd}, HW_Category_SIMDScalar, HW_Flag_MultiIns|HW_Flag_NoContainment|HW_Flag_NoRMWSemantics) HARDWARE_INTRINSIC(SSE2_CompareLessThan, "CompareLessThan", SSE2, 1, 16, 2, {INS_pcmpgtb, INS_invalid, INS_pcmpgtw, INS_invalid, INS_pcmpgtd, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmppd}, HW_Category_Special, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(SSE2_CompareLessThanOrderedScalar, "CompareLessThanOrderedScalar", SSE2, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_comisd}, HW_Category_SIMDScalar, HW_Flag_MultiIns|HW_Flag_NoContainment) +HARDWARE_INTRINSIC(SSE2_CompareLessThanOrderedScalar, "CompareLessThanOrderedScalar", SSE2, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_comisd}, HW_Category_SIMDScalar, HW_Flag_MultiIns|HW_Flag_NoContainment|HW_Flag_NoRMWSemantics) HARDWARE_INTRINSIC(SSE2_CompareLessThanScalar, "CompareLessThanScalar", SSE2, 1, 16, 2, {INS_pcmpgtb, INS_invalid, INS_pcmpgtw, INS_invalid, INS_pcmpgtd, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpsd}, HW_Category_SIMDScalar, HW_Flag_BaseTypeFromArg|HW_Flag_CopyUpperBits) -HARDWARE_INTRINSIC(SSE2_CompareLessThanUnorderedScalar, "CompareLessThanUnorderedScalar", SSE2, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_ucomisd}, HW_Category_SIMDScalar, HW_Flag_MultiIns|HW_Flag_NoContainment) +HARDWARE_INTRINSIC(SSE2_CompareLessThanUnorderedScalar, "CompareLessThanUnorderedScalar", SSE2, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_ucomisd}, HW_Category_SIMDScalar, HW_Flag_MultiIns|HW_Flag_NoContainment|HW_Flag_NoRMWSemantics) HARDWARE_INTRINSIC(SSE2_CompareLessThanOrEqual, "CompareLessThanOrEqual", SSE2, 2, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmppd}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(SSE2_CompareLessThanOrEqualOrderedScalar, "CompareLessThanOrEqualOrderedScalar", SSE2, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_comisd}, HW_Category_SIMDScalar, HW_Flag_MultiIns|HW_Flag_NoContainment) +HARDWARE_INTRINSIC(SSE2_CompareLessThanOrEqualOrderedScalar, "CompareLessThanOrEqualOrderedScalar", SSE2, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_comisd}, HW_Category_SIMDScalar, HW_Flag_MultiIns|HW_Flag_NoContainment|HW_Flag_NoRMWSemantics) HARDWARE_INTRINSIC(SSE2_CompareLessThanOrEqualScalar, "CompareLessThanOrEqualScalar", SSE2, 2, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpsd}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) -HARDWARE_INTRINSIC(SSE2_CompareLessThanOrEqualUnorderedScalar, "CompareLessThanOrEqualUnorderedScalar", SSE2, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_ucomisd}, HW_Category_SIMDScalar, HW_Flag_MultiIns|HW_Flag_NoContainment) +HARDWARE_INTRINSIC(SSE2_CompareLessThanOrEqualUnorderedScalar, "CompareLessThanOrEqualUnorderedScalar", SSE2, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_ucomisd}, HW_Category_SIMDScalar, HW_Flag_MultiIns|HW_Flag_NoContainment|HW_Flag_NoRMWSemantics) HARDWARE_INTRINSIC(SSE2_CompareNotEqual, "CompareNotEqual", SSE2, 4, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmppd}, HW_Category_SimpleSIMD, HW_Flag_Commutative) -HARDWARE_INTRINSIC(SSE2_CompareNotEqualOrderedScalar, "CompareNotEqualOrderedScalar", SSE2, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_comisd}, HW_Category_SIMDScalar, HW_Flag_MultiIns|HW_Flag_NoContainment) +HARDWARE_INTRINSIC(SSE2_CompareNotEqualOrderedScalar, "CompareNotEqualOrderedScalar", SSE2, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_comisd}, HW_Category_SIMDScalar, HW_Flag_MultiIns|HW_Flag_NoContainment|HW_Flag_NoRMWSemantics) HARDWARE_INTRINSIC(SSE2_CompareNotEqualScalar, "CompareNotEqualScalar", SSE2, 4, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpsd}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) -HARDWARE_INTRINSIC(SSE2_CompareNotEqualUnorderedScalar, "CompareNotEqualUnorderedScalar", SSE2, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_ucomisd}, HW_Category_SIMDScalar, HW_Flag_MultiIns|HW_Flag_NoContainment) +HARDWARE_INTRINSIC(SSE2_CompareNotEqualUnorderedScalar, "CompareNotEqualUnorderedScalar", SSE2, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_ucomisd}, HW_Category_SIMDScalar, HW_Flag_MultiIns|HW_Flag_NoContainment|HW_Flag_NoRMWSemantics) HARDWARE_INTRINSIC(SSE2_CompareNotGreaterThan, "CompareNotGreaterThan", SSE2, 2, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmppd}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) HARDWARE_INTRINSIC(SSE2_CompareNotGreaterThanScalar, "CompareNotGreaterThanScalar", SSE2, 2, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpsd}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) HARDWARE_INTRINSIC(SSE2_CompareNotGreaterThanOrEqual, "CompareNotGreaterThanOrEqual", SSE2, 1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmppd}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) @@ -169,35 +169,35 @@ HARDWARE_INTRINSIC(SSE2_CompareOrdered, "CompareOrd HARDWARE_INTRINSIC(SSE2_CompareOrderedScalar, "CompareOrderedScalar", SSE2, 7, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpsd}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) HARDWARE_INTRINSIC(SSE2_CompareUnordered, "CompareUnordered", SSE2, 3, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmppd}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) HARDWARE_INTRINSIC(SSE2_CompareUnorderedScalar, "CompareUnorderedScalar", SSE2, 3, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpsd}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) -HARDWARE_INTRINSIC(SSE2_ConvertToDouble, "ConvertToDouble", SSE2, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movsd}, HW_Category_Helper, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(SSE2_ConvertToInt32, "ConvertToInt32", SSE2, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_mov_xmm2i, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cvtsd2si}, HW_Category_Special, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(SSE2_ConvertToInt32WithTruncation, "ConvertToInt32WithTruncation", SSE2, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cvttsd2si}, HW_Category_SIMDScalar, HW_Flag_BaseTypeFromArg) -HARDWARE_INTRINSIC(SSE2_ConvertToInt64, "ConvertToInt64", SSE2, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_mov_xmm2i, INS_invalid, INS_invalid, INS_cvtsd2si}, HW_Category_Special, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(SSE2_ConvertToInt64WithTruncation, "ConvertToInt64WithTruncation", SSE2, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cvttsd2si}, HW_Category_SIMDScalar, HW_Flag_BaseTypeFromArg) -HARDWARE_INTRINSIC(SSE2_ConvertToUInt32, "ConvertToUInt32", SSE2, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_mov_xmm2i, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Special, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(SSE2_ConvertToUInt64, "ConvertToUInt64", SSE2, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_mov_xmm2i, INS_invalid, INS_invalid}, HW_Category_Special, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(SSE2_ConvertToVector128Double, "ConvertToVector128Double", SSE2, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cvtdq2pd, INS_invalid, INS_invalid, INS_invalid, INS_cvtps2pd, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_BaseTypeFromArg) -HARDWARE_INTRINSIC(SSE2_ConvertScalarToVector128Double, "ConvertScalarToVector128Double", SSE2, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cvtsi2sd, INS_invalid, INS_cvtsi2sd, INS_invalid, INS_cvtss2sd, INS_invalid}, HW_Category_Special, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(SSE2_ConvertToVector128Int32, "ConvertToVector128Int32", SSE2, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cvtps2dq, INS_cvtpd2dq}, HW_Category_SimpleSIMD, HW_Flag_BaseTypeFromArg) -HARDWARE_INTRINSIC(SSE2_ConvertScalarToVector128Int32, "ConvertScalarToVector128Int32", SSE2, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_mov_i2xmm, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(SSE2_ConvertToVector128Int32WithTruncation, "ConvertToVector128Int32WithTruncation", SSE2, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cvttps2dq, INS_cvttpd2dq}, HW_Category_SimpleSIMD, HW_Flag_BaseTypeFromArg) -HARDWARE_INTRINSIC(SSE2_ConvertScalarToVector128Int64, "ConvertScalarToVector128Int64", SSE2, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_mov_i2xmm, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Special, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(SSE2_ConvertToVector128Single, "ConvertToVector128Single", SSE2, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cvtdq2ps, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cvtpd2ps}, HW_Category_SimpleSIMD, HW_Flag_BaseTypeFromArg) -HARDWARE_INTRINSIC(SSE2_ConvertScalarToVector128Single, "ConvertScalarToVector128Single", SSE2, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cvtsd2ss}, HW_Category_Special, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(SSE2_ConvertScalarToVector128UInt32, "ConvertScalarToVector128UInt32", SSE2, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_mov_i2xmm, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(SSE2_ConvertScalarToVector128UInt64, "ConvertScalarToVector128UInt64", SSE2, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_mov_i2xmm, INS_invalid, INS_invalid}, HW_Category_Special, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(SSE2_ConvertToDouble, "ConvertToDouble", SSE2, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movsd}, HW_Category_Helper, HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE2_ConvertToInt32, "ConvertToInt32", SSE2, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_mov_xmm2i, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cvtsd2si}, HW_Category_Special, HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE2_ConvertToInt32WithTruncation, "ConvertToInt32WithTruncation", SSE2, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cvttsd2si}, HW_Category_SIMDScalar, HW_Flag_BaseTypeFromArg|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE2_ConvertToInt64, "ConvertToInt64", SSE2, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_mov_xmm2i, INS_invalid, INS_invalid, INS_cvtsd2si}, HW_Category_Special, HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE2_ConvertToInt64WithTruncation, "ConvertToInt64WithTruncation", SSE2, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cvttsd2si}, HW_Category_SIMDScalar, HW_Flag_BaseTypeFromArg|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE2_ConvertToUInt32, "ConvertToUInt32", SSE2, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_mov_xmm2i, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Special, HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE2_ConvertToUInt64, "ConvertToUInt64", SSE2, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_mov_xmm2i, INS_invalid, INS_invalid}, HW_Category_Special, HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE2_ConvertToVector128Double, "ConvertToVector128Double", SSE2, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cvtdq2pd, INS_invalid, INS_invalid, INS_invalid, INS_cvtps2pd, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_BaseTypeFromArg|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE2_ConvertScalarToVector128Double, "ConvertScalarToVector128Double", SSE2, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cvtsi2sd, INS_invalid, INS_cvtsi2sd, INS_invalid, INS_cvtss2sd, INS_invalid}, HW_Category_Special, HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE2_ConvertToVector128Int32, "ConvertToVector128Int32", SSE2, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cvtps2dq, INS_cvtpd2dq}, HW_Category_SimpleSIMD, HW_Flag_BaseTypeFromArg|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE2_ConvertScalarToVector128Int32, "ConvertScalarToVector128Int32", SSE2, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_mov_i2xmm, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE2_ConvertToVector128Int32WithTruncation, "ConvertToVector128Int32WithTruncation", SSE2, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cvttps2dq, INS_cvttpd2dq}, HW_Category_SimpleSIMD, HW_Flag_BaseTypeFromArg|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE2_ConvertScalarToVector128Int64, "ConvertScalarToVector128Int64", SSE2, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_mov_i2xmm, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Special, HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE2_ConvertToVector128Single, "ConvertToVector128Single", SSE2, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cvtdq2ps, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cvtpd2ps}, HW_Category_SimpleSIMD, HW_Flag_BaseTypeFromArg|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE2_ConvertScalarToVector128Single, "ConvertScalarToVector128Single", SSE2, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cvtsd2ss}, HW_Category_Special, HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE2_ConvertScalarToVector128UInt32, "ConvertScalarToVector128UInt32", SSE2, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_mov_i2xmm, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE2_ConvertScalarToVector128UInt64, "ConvertScalarToVector128UInt64", SSE2, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_mov_i2xmm, INS_invalid, INS_invalid}, HW_Category_Special, HW_Flag_NoRMWSemantics) HARDWARE_INTRINSIC(SSE2_Divide, "Divide", SSE2, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_divpd}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) HARDWARE_INTRINSIC(SSE2_DivideScalar, "DivideScalar", SSE2, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_divsd}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) -HARDWARE_INTRINSIC(SSE2_LoadAlignedVector128, "LoadAlignedVector128", SSE2, -1, 16, 1, {INS_movdqa, INS_movdqa, INS_movdqa, INS_movdqa, INS_movdqa, INS_movdqa, INS_movdqa, INS_movdqa, INS_invalid, INS_movapd}, HW_Category_MemoryLoad, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(SSE2_LoadFence, "LoadFence", SSE2, -1, 0, 0, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Special, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(SSE2_LoadScalarVector128, "LoadScalarVector128", SSE2, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movd, INS_movd, INS_movq, INS_movq, INS_invalid, INS_movsdsse2}, HW_Category_MemoryLoad, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(SSE2_LoadVector128, "LoadVector128", SSE2, -1, 16, 1, {INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_invalid, INS_movupd}, HW_Category_MemoryLoad, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(SSE2_LoadAlignedVector128, "LoadAlignedVector128", SSE2, -1, 16, 1, {INS_movdqa, INS_movdqa, INS_movdqa, INS_movdqa, INS_movdqa, INS_movdqa, INS_movdqa, INS_movdqa, INS_invalid, INS_movapd}, HW_Category_MemoryLoad, HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE2_LoadFence, "LoadFence", SSE2, -1, 0, 0, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Special, HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE2_LoadScalarVector128, "LoadScalarVector128", SSE2, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movd, INS_movd, INS_movq, INS_movq, INS_invalid, INS_movsdsse2}, HW_Category_MemoryLoad, HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE2_LoadVector128, "LoadVector128", SSE2, -1, 16, 1, {INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_invalid, INS_movupd}, HW_Category_MemoryLoad, HW_Flag_NoRMWSemantics) HARDWARE_INTRINSIC(SSE2_Max, "Max", SSE2, -1, 16, 2, {INS_invalid, INS_pmaxub, INS_pmaxsw, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_maxpd}, HW_Category_SimpleSIMD, HW_Flag_Commutative) -HARDWARE_INTRINSIC(SSE2_MemoryFence, "MemoryFence", SSE2, -1, 0, 0, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Special, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(SSE2_MemoryFence, "MemoryFence", SSE2, -1, 0, 0, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Special, HW_Flag_NoRMWSemantics) HARDWARE_INTRINSIC(SSE2_MaxScalar, "MaxScalar", SSE2, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_maxsd}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) HARDWARE_INTRINSIC(SSE2_Min, "Min", SSE2, -1, 16, 2, {INS_invalid, INS_pminub, INS_pminsw, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_minpd}, HW_Category_SimpleSIMD, HW_Flag_Commutative) HARDWARE_INTRINSIC(SSE2_MinScalar, "MinScalar", SSE2, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_minsd}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) -HARDWARE_INTRINSIC(SSE2_MoveMask, "MoveMask", SSE2, -1, 16, 1, {INS_pmovmskb, INS_pmovmskb, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movmskpd}, HW_Category_Special, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(SSE2_MoveMask, "MoveMask", SSE2, -1, 16, 1, {INS_pmovmskb, INS_pmovmskb, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movmskpd}, HW_Category_Special, HW_Flag_NoRMWSemantics) HARDWARE_INTRINSIC(SSE2_MoveScalar, "MoveScalar", SSE2, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movsdsse2}, HW_Category_SIMDScalar, HW_Flag_NoContainment) HARDWARE_INTRINSIC(SSE2_Multiply, "Multiply", SSE2, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_pmuludq, INS_invalid, INS_invalid, INS_invalid, INS_mulpd}, HW_Category_SimpleSIMD, HW_Flag_Commutative|HW_Flag_BaseTypeFromArg) HARDWARE_INTRINSIC(SSE2_MultiplyHigh, "MultiplyHigh", SSE2, -1, 16, 2, {INS_invalid, INS_invalid, INS_pmulhw, INS_pmulhuw, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_Commutative) @@ -207,21 +207,21 @@ HARDWARE_INTRINSIC(SSE2_MultiplyScalar, "MultiplySc HARDWARE_INTRINSIC(SSE2_Or, "Or", SSE2, -1, 16, 2, {INS_por, INS_por, INS_por, INS_por, INS_por, INS_por, INS_por, INS_por, INS_invalid, INS_orpd}, HW_Category_SimpleSIMD, HW_Flag_Commutative) HARDWARE_INTRINSIC(SSE2_PackSignedSaturate, "PackSignedSaturate", SSE2, -1, 16, 2, {INS_invalid, INS_invalid, INS_packsswb, INS_invalid, INS_packssdw, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_BaseTypeFromArg) HARDWARE_INTRINSIC(SSE2_PackUnsignedSaturate, "PackUnsignedSaturate", SSE2, -1, 16, 2, {INS_invalid, INS_invalid, INS_packuswb, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_BaseTypeFromArg) -HARDWARE_INTRINSIC(SSE2_SetZeroVector128, "SetZeroVector128", SSE2, -1, 16, 0, {INS_pxor, INS_pxor, INS_pxor, INS_pxor, INS_pxor, INS_pxor, INS_pxor, INS_pxor, INS_invalid, INS_xorpd}, HW_Category_Helper, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(SSE2_SetZeroVector128, "SetZeroVector128", SSE2, -1, 16, 0, {INS_pxor, INS_pxor, INS_pxor, INS_pxor, INS_pxor, INS_pxor, INS_pxor, INS_pxor, INS_invalid, INS_xorpd}, HW_Category_Helper, HW_Flag_NoRMWSemantics) HARDWARE_INTRINSIC(SSE2_SumAbsoluteDifferences, "SumAbsoluteDifferences", SSE2, -1, 16, 2, {INS_invalid, INS_psadbw, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_BaseTypeFromArg) HARDWARE_INTRINSIC(SSE2_ShiftLeftLogical, "ShiftLeftLogical", SSE2, -1, 16, 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(SSE2_ShiftLeftLogical128BitLane, "ShiftLeftLogical128BitLane", SSE2, -1, 16, 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(SSE2_ShiftRightArithmetic, "ShiftRightArithmetic", SSE2, -1, 16, 2, {INS_invalid, INS_invalid, INS_psraw, INS_invalid, INS_psrad, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_MaybeIMM|HW_Flag_NoJmpTableIMM|HW_Flag_FullRangeIMM) HARDWARE_INTRINSIC(SSE2_ShiftRightLogical, "ShiftRightLogical", SSE2, -1, 16, 2, {INS_invalid, INS_invalid, INS_psrlw, INS_psrlw, INS_psrld, INS_psrld, INS_psrlq, INS_psrlq, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_MaybeIMM|HW_Flag_NoJmpTableIMM|HW_Flag_FullRangeIMM) HARDWARE_INTRINSIC(SSE2_ShiftRightLogical128BitLane, "ShiftRightLogical128BitLane", SSE2, -1, 16, 2, {INS_psrldq, INS_psrldq, INS_psrldq, INS_psrldq, INS_psrldq, INS_psrldq, INS_psrldq, INS_psrldq, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_FullRangeIMM) -HARDWARE_INTRINSIC(SSE2_Sqrt, "Sqrt", SSE2, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sqrtpd}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(SSE2_SqrtScalar, "SqrtScalar", SSE2, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sqrtsd}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) -HARDWARE_INTRINSIC(SSE2_Store, "Store", SSE2, -1, 16, 2, {INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_invalid, INS_movupd}, HW_Category_MemoryStore, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(SSE2_StoreAligned, "StoreAligned", SSE2, -1, 16, 2, {INS_movdqa, INS_movdqa, INS_movdqa, INS_movdqa, INS_movdqa, INS_movdqa, INS_movdqa, INS_movdqa, INS_invalid, INS_movapd}, HW_Category_MemoryStore, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(SSE2_StoreAlignedNonTemporal, "StoreAlignedNonTemporal", SSE2, -1, 16, 2, {INS_movntdq, INS_movntdq, INS_movntdq, INS_movntdq, INS_movntdq, INS_movntdq, INS_movntdq, INS_movntdq, INS_invalid, INS_movntpd}, HW_Category_MemoryStore, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(SSE2_StoreScalar, "StoreScalar", SSE2, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movsdsse2}, HW_Category_MemoryStore, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(SSE2_StoreLow, "StoreLow", SSE2, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movq, INS_movq, INS_invalid, INS_movlpd}, HW_Category_MemoryStore, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(SSE2_StoreHigh, "StoreHigh", SSE2, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movhpd}, HW_Category_MemoryStore, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(SSE2_Sqrt, "Sqrt", SSE2, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sqrtpd}, HW_Category_SimpleSIMD, HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE2_SqrtScalar, "SqrtScalar", SSE2, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sqrtsd}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE2_Store, "Store", SSE2, -1, 16, 2, {INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_invalid, INS_movupd}, HW_Category_MemoryStore, HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE2_StoreAligned, "StoreAligned", SSE2, -1, 16, 2, {INS_movdqa, INS_movdqa, INS_movdqa, INS_movdqa, INS_movdqa, INS_movdqa, INS_movdqa, INS_movdqa, INS_invalid, INS_movapd}, HW_Category_MemoryStore, HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE2_StoreAlignedNonTemporal, "StoreAlignedNonTemporal", SSE2, -1, 16, 2, {INS_movntdq, INS_movntdq, INS_movntdq, INS_movntdq, INS_movntdq, INS_movntdq, INS_movntdq, INS_movntdq, INS_invalid, INS_movntpd}, HW_Category_MemoryStore, HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE2_StoreScalar, "StoreScalar", SSE2, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movsdsse2}, HW_Category_MemoryStore, HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE2_StoreLow, "StoreLow", SSE2, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movq, INS_movq, INS_invalid, INS_movlpd}, HW_Category_MemoryStore, HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE2_StoreHigh, "StoreHigh", SSE2, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movhpd}, HW_Category_MemoryStore, HW_Flag_NoRMWSemantics) HARDWARE_INTRINSIC(SSE2_Subtract, "Subtract", SSE2, -1, 16, 2, {INS_psubb, INS_psubb, INS_psubw, INS_psubw, INS_psubd, INS_psubd, INS_psubq, INS_psubq, INS_invalid, INS_subpd}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) HARDWARE_INTRINSIC(SSE2_SubtractSaturate, "SubtractSaturate", SSE2, -1, 16, 2, {INS_psubsb, INS_psubusb, INS_psubsw, INS_psubusw, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) HARDWARE_INTRINSIC(SSE2_SubtractScalar, "SubtractScalar", SSE2, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_subsd}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) @@ -238,11 +238,11 @@ HARDWARE_INTRINSIC(SSE3_IsSupported, "get_IsSupp HARDWARE_INTRINSIC(SSE3_AddSubtract, "AddSubtract", SSE3, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_addsubps, INS_addsubpd}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) HARDWARE_INTRINSIC(SSE3_HorizontalAdd, "HorizontalAdd", SSE3, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_haddps, INS_haddpd}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) HARDWARE_INTRINSIC(SSE3_HorizontalSubtract, "HorizontalSubtract", SSE3, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_hsubps, INS_hsubpd}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(SSE3_LoadAndDuplicateToVector128, "LoadAndDuplicateToVector128", SSE3, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_lddqu, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movddup}, HW_Category_MemoryLoad, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(SSE3_LoadDquVector128, "LoadDquVector128", SSE3, -1, 16, 1, {INS_lddqu, INS_lddqu, INS_lddqu, INS_lddqu, INS_lddqu, INS_lddqu, INS_lddqu, INS_lddqu, INS_invalid, INS_invalid}, HW_Category_MemoryLoad, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(SSE3_MoveAndDuplicate, "MoveAndDuplicate", SSE3, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movddup}, HW_Category_SimpleSIMD, HW_Flag_NoContainment) -HARDWARE_INTRINSIC(SSE3_MoveHighAndDuplicate, "MoveHighAndDuplicate", SSE3, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movshdup, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoContainment) -HARDWARE_INTRINSIC(SSE3_MoveLowAndDuplicate, "MoveLowAndDuplicate", SSE3, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movsldup, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoContainment) +HARDWARE_INTRINSIC(SSE3_LoadAndDuplicateToVector128, "LoadAndDuplicateToVector128", SSE3, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_lddqu, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movddup}, HW_Category_MemoryLoad, HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE3_LoadDquVector128, "LoadDquVector128", SSE3, -1, 16, 1, {INS_lddqu, INS_lddqu, INS_lddqu, INS_lddqu, INS_lddqu, INS_lddqu, INS_lddqu, INS_lddqu, INS_invalid, INS_invalid}, HW_Category_MemoryLoad, HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE3_MoveAndDuplicate, "MoveAndDuplicate", SSE3, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movddup}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE3_MoveHighAndDuplicate, "MoveHighAndDuplicate", SSE3, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movshdup, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE3_MoveLowAndDuplicate, "MoveLowAndDuplicate", SSE3, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movsldup, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_NoRMWSemantics) // ************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************ // Intrinsic ID Function name ISA ival SIMD size NumArg instructions Category Flags @@ -250,7 +250,7 @@ HARDWARE_INTRINSIC(SSE3_MoveLowAndDuplicate, "MoveLowAnd // ************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************ // SSSE3 Intrinsics HARDWARE_INTRINSIC(SSSE3_IsSupported, "get_IsSupported", SSSE3, -1, 0, 0, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_IsSupportedProperty, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(SSSE3_Abs, "Abs", SSSE3, -1, 16, 1, {INS_invalid, INS_pabsb, INS_invalid, INS_pabsw, INS_invalid, INS_pabsd, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(SSSE3_Abs, "Abs", SSSE3, -1, 16, 1, {INS_invalid, INS_pabsb, INS_invalid, INS_pabsw, INS_invalid, INS_pabsd, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoRMWSemantics) HARDWARE_INTRINSIC(SSSE3_AlignRight, "AlignRight", SSSE3, -1, 16, 3, {INS_palignr, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_FullRangeIMM) HARDWARE_INTRINSIC(SSSE3_HorizontalAdd, "HorizontalAdd", SSSE3, -1, 16, 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(SSSE3_HorizontalAddSaturate, "HorizontalAddSaturate", SSSE3, -1, 16, 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) @@ -269,34 +269,34 @@ HARDWARE_INTRINSIC(SSSE3_Sign, "Sign", HARDWARE_INTRINSIC(SSE41_IsSupported, "get_IsSupported", SSE41, -1, 0, 0, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_IsSupportedProperty, HW_Flag_NoFlag) HARDWARE_INTRINSIC(SSE41_Blend, "Blend", SSE41, -1, 16, 3, {INS_invalid, INS_invalid, INS_pblendw, INS_pblendw, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_blendps, INS_blendpd}, HW_Category_IMM, HW_Flag_FullRangeIMM) HARDWARE_INTRINSIC(SSE41_BlendVariable, "BlendVariable", SSE41, -1, 16, 3, {INS_pblendvb, INS_pblendvb, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_blendvps, INS_blendvpd}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(SSE41_Ceiling, "Ceiling", SSE41, 10, 16, 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_NoFlag) +HARDWARE_INTRINSIC(SSE41_Ceiling, "Ceiling", SSE41, 10, 16, 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(SSE41_CeilingScalar, "CeilingScalar", SSE41, 10, 16, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_roundss, INS_roundsd}, HW_Category_Special, HW_Flag_CopyUpperBits) HARDWARE_INTRINSIC(SSE41_CompareEqual, "CompareEqual", SSE41, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_pcmpeqq, INS_pcmpeqq, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_Commutative) -HARDWARE_INTRINSIC(SSE41_ConvertToVector128Int16, "ConvertToVector128Int16", SSE41, -1, 16, 1, {INS_pmovsxbw, INS_pmovzxbw, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_BaseTypeFromArg) -HARDWARE_INTRINSIC(SSE41_ConvertToVector128Int32, "ConvertToVector128Int32", SSE41, -1, 16, 1, {INS_pmovsxbd, INS_pmovzxbd, INS_pmovsxwd, INS_pmovzxwd, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_BaseTypeFromArg) -HARDWARE_INTRINSIC(SSE41_ConvertToVector128Int64, "ConvertToVector128Int64", SSE41, -1, 16, 1, {INS_pmovsxbq, INS_pmovzxbq, INS_pmovsxwq, INS_pmovzxwq, INS_pmovsxdq, INS_pmovzxdq, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_BaseTypeFromArg) +HARDWARE_INTRINSIC(SSE41_ConvertToVector128Int16, "ConvertToVector128Int16", SSE41, -1, 16, 1, {INS_pmovsxbw, INS_pmovzxbw, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_BaseTypeFromArg|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE41_ConvertToVector128Int32, "ConvertToVector128Int32", SSE41, -1, 16, 1, {INS_pmovsxbd, INS_pmovzxbd, INS_pmovsxwd, INS_pmovzxwd, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_BaseTypeFromArg|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE41_ConvertToVector128Int64, "ConvertToVector128Int64", SSE41, -1, 16, 1, {INS_pmovsxbq, INS_pmovzxbq, INS_pmovsxwq, INS_pmovzxwq, INS_pmovsxdq, INS_pmovzxdq, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_BaseTypeFromArg|HW_Flag_NoRMWSemantics) HARDWARE_INTRINSIC(SSE41_DotProduct, "DotProduct", SSE41, -1, 16, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_dpps, INS_dppd}, HW_Category_IMM, HW_Flag_FullRangeIMM) -HARDWARE_INTRINSIC(SSE41_Floor, "Floor", SSE41, 9, 16, 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_NoFlag) +HARDWARE_INTRINSIC(SSE41_Floor, "Floor", SSE41, 9, 16, 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(SSE41_FloorScalar, "FloorScalar", SSE41, 9, 16, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_roundss, INS_roundsd}, HW_Category_Special, HW_Flag_CopyUpperBits) -HARDWARE_INTRINSIC(SSE41_LoadAlignedVector128NonTemporal, "LoadAlignedVector128NonTemporal", SSE41, -1, 16, 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_NoFlag) +HARDWARE_INTRINSIC(SSE41_LoadAlignedVector128NonTemporal, "LoadAlignedVector128NonTemporal", SSE41, -1, 16, 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(SSE41_Max, "Max", SSE41, -1, 16, 2, {INS_pmaxsb, INS_invalid, INS_invalid, INS_pmaxuw, INS_pmaxsd, INS_pmaxud, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) HARDWARE_INTRINSIC(SSE41_Min, "Min", SSE41, -1, 16, 2, {INS_pminsb, INS_invalid, INS_invalid, INS_pminuw, INS_pminsd, INS_pminud, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(SSE41_MinHorizontal, "MinHorizontal", SSE41, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_phminposuw, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(SSE41_MinHorizontal, "MinHorizontal", SSE41, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_phminposuw, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoRMWSemantics) HARDWARE_INTRINSIC(SSE41_MultipleSumAbsoluteDifferences, "MultipleSumAbsoluteDifferences", SSE41, -1, 16, 3, {INS_invalid, INS_invalid, INS_invalid, INS_mpsadbw, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_FullRangeIMM) HARDWARE_INTRINSIC(SSE41_Multiply, "Multiply", SSE41, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_pmuldq, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_Commutative) HARDWARE_INTRINSIC(SSE41_MultiplyLow, "MultiplyLow", SSE41, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_pmulld, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) HARDWARE_INTRINSIC(SSE41_PackUnsignedSaturate, "PackUnsignedSaturate", SSE41, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_packusdw, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(SSE41_RoundCurrentDirection, "RoundCurrentDirection", SSE41, 4, 16, 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_NoFlag) +HARDWARE_INTRINSIC(SSE41_RoundCurrentDirection, "RoundCurrentDirection", SSE41, 4, 16, 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(SSE41_RoundCurrentDirectionScalar, "RoundCurrentDirectionScalar", SSE41, 4, 16, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_roundss, INS_roundsd}, HW_Category_Special, HW_Flag_CopyUpperBits) -HARDWARE_INTRINSIC(SSE41_RoundToNearestInteger, "RoundToNearestInteger", SSE41, 8, 16, 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_NoFlag) +HARDWARE_INTRINSIC(SSE41_RoundToNearestInteger, "RoundToNearestInteger", SSE41, 8, 16, 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(SSE41_RoundToNearestIntegerScalar, "RoundToNearestIntegerScalar", SSE41, 8, 16, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_roundss, INS_roundsd}, HW_Category_Special, HW_Flag_CopyUpperBits) -HARDWARE_INTRINSIC(SSE41_RoundToNegativeInfinity, "RoundToNegativeInfinity", SSE41, 9, 16, 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_NoFlag) +HARDWARE_INTRINSIC(SSE41_RoundToNegativeInfinity, "RoundToNegativeInfinity", SSE41, 9, 16, 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(SSE41_RoundToNegativeInfinityScalar, "RoundToNegativeInfinityScalar", SSE41, 9, 16, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_roundss, INS_roundsd}, HW_Category_Special, HW_Flag_CopyUpperBits) -HARDWARE_INTRINSIC(SSE41_RoundToPositiveInfinity, "RoundToPositiveInfinity", SSE41, 10, 16, 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_NoFlag) +HARDWARE_INTRINSIC(SSE41_RoundToPositiveInfinity, "RoundToPositiveInfinity", SSE41, 10, 16, 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(SSE41_RoundToPositiveInfinityScalar, "RoundToPositiveInfinityScalar", SSE41, 10, 16, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_roundss, INS_roundsd}, HW_Category_Special, HW_Flag_CopyUpperBits) -HARDWARE_INTRINSIC(SSE41_RoundToZero, "RoundToZero", SSE41, 11, 16, 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_NoFlag) +HARDWARE_INTRINSIC(SSE41_RoundToZero, "RoundToZero", SSE41, 11, 16, 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(SSE41_RoundToZeroScalar, "RoundToZeroScalar", SSE41, 11, 16, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_roundss, INS_roundsd}, HW_Category_Special, HW_Flag_CopyUpperBits) -HARDWARE_INTRINSIC(SSE41_TestAllOnes, "TestAllOnes", SSE41, -1, 16, 1, {INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_MultiIns|HW_Flag_NoContainment) +HARDWARE_INTRINSIC(SSE41_TestAllOnes, "TestAllOnes", SSE41, -1, 16, 1, {INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_MultiIns|HW_Flag_NoContainment|HW_Flag_NoRMWSemantics) HARDWARE_INTRINSIC(SSE41_TestAllZeros, "TestAllZeros", SSE41, -1, 16, 2, {INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_MultiIns|HW_Flag_NoContainment) HARDWARE_INTRINSIC(SSE41_TestC, "TestC", SSE41, -1, 16, 2, {INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_MultiIns|HW_Flag_NoContainment) HARDWARE_INTRINSIC(SSE41_TestMixOnesZeros, "TestMixOnesZeros", SSE41, -1, 16, 2, {INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_MultiIns|HW_Flag_NoContainment) @@ -321,26 +321,26 @@ HARDWARE_INTRINSIC(AVX_AddSubtract, "AddSubtrac HARDWARE_INTRINSIC(AVX_BlendVariable, "BlendVariable", AVX, -1, 32, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vblendvps, INS_vblendvpd}, HW_Category_SimpleSIMD, 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_NoFlag) +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) HARDWARE_INTRINSIC(AVX_Divide, "Divide", AVX, -1, 32, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_divps, INS_divpd}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(AVX_DuplicateEvenIndexed, "DuplicateEvenIndexed", AVX, -1, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movsldup, INS_movddup}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(AVX_DuplicateOddIndexed, "DuplicateOddIndexed", AVX, -1, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movshdup, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AVX_DuplicateEvenIndexed, "DuplicateEvenIndexed", AVX, -1, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movsldup, INS_movddup}, HW_Category_SimpleSIMD, HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(AVX_DuplicateOddIndexed, "DuplicateOddIndexed", AVX, -1, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movshdup, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoRMWSemantics) HARDWARE_INTRINSIC(AVX_HorizontalAdd, "HorizontalAdd", AVX, -1, 32, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_haddps, INS_haddpd}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) HARDWARE_INTRINSIC(AVX_HorizontalSubtract, "HorizontalSubtract", AVX, -1, 32, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_hsubps, INS_hsubpd}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(AVX_LoadAlignedVector256, "LoadAlignedVector256", AVX, -1, 32, 1, {INS_movdqa, INS_movdqa, INS_movdqa, INS_movdqa, INS_movdqa, INS_movdqa, INS_movdqa, INS_movdqa, INS_movaps, INS_movapd}, HW_Category_MemoryLoad, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(AVX_LoadDquVector256, "LoadDquVector256", AVX, -1, 32, 1, {INS_lddqu, INS_lddqu, INS_lddqu, INS_lddqu, INS_lddqu, INS_lddqu, INS_lddqu, INS_lddqu, INS_invalid, INS_invalid}, HW_Category_MemoryLoad, HW_Flag_NoFlag) -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_NoFlag) +HARDWARE_INTRINSIC(AVX_LoadAlignedVector256, "LoadAlignedVector256", AVX, -1, 32, 1, {INS_movdqa, INS_movdqa, INS_movdqa, INS_movdqa, INS_movdqa, INS_movdqa, INS_movdqa, INS_movdqa, INS_movaps, INS_movapd}, HW_Category_MemoryLoad, HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(AVX_LoadDquVector256, "LoadDquVector256", AVX, -1, 32, 1, {INS_lddqu, INS_lddqu, INS_lddqu, INS_lddqu, INS_lddqu, INS_lddqu, INS_lddqu, INS_lddqu, INS_invalid, INS_invalid}, HW_Category_MemoryLoad, HW_Flag_NoRMWSemantics) +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_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_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_NoFlag) -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_NoFlag) -HARDWARE_INTRINSIC(AVX_SetZeroVector256, "SetZeroVector256", AVX, -1, 32, 0, {INS_pxor, INS_pxor, INS_pxor, INS_pxor, INS_pxor, INS_pxor, INS_pxor, INS_pxor, INS_xorps, INS_xorpd}, HW_Category_Helper, HW_Flag_OneTypeGeneric) -HARDWARE_INTRINSIC(AVX_Sqrt, "Sqrt", AVX, -1, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sqrtps, INS_sqrtpd}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(AVX_Store, "Store", AVX, -1, 32, 2, {INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movups, INS_movupd}, HW_Category_MemoryStore, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(AVX_StoreAligned, "StoreAligned", AVX, -1, 32, 2, {INS_movdqa, INS_movdqa, INS_movdqa, INS_movdqa, INS_movdqa, INS_movdqa, INS_movdqa, INS_movdqa, INS_movaps, INS_movapd}, HW_Category_MemoryStore, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(AVX_StoreAlignedNonTemporal, "StoreAlignedNonTemporal", AVX, -1, 32, 2, {INS_movntdq, INS_movntdq, INS_movntdq, INS_movntdq, INS_movntdq, INS_movntdq, INS_movntdq, INS_movntdq, INS_movntps, INS_movntpd}, HW_Category_MemoryStore, HW_Flag_NoFlag) +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_SetZeroVector256, "SetZeroVector256", AVX, -1, 32, 0, {INS_pxor, INS_pxor, INS_pxor, INS_pxor, INS_pxor, INS_pxor, INS_pxor, INS_pxor, INS_xorps, INS_xorpd}, HW_Category_Helper, HW_Flag_OneTypeGeneric|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(AVX_Sqrt, "Sqrt", AVX, -1, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sqrtps, INS_sqrtpd}, HW_Category_SimpleSIMD, HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(AVX_Store, "Store", AVX, -1, 32, 2, {INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movups, INS_movupd}, HW_Category_MemoryStore, HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(AVX_StoreAligned, "StoreAligned", AVX, -1, 32, 2, {INS_movdqa, INS_movdqa, INS_movdqa, INS_movdqa, INS_movdqa, INS_movdqa, INS_movdqa, INS_movdqa, INS_movaps, INS_movapd}, HW_Category_MemoryStore, HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(AVX_StoreAlignedNonTemporal, "StoreAlignedNonTemporal", AVX, -1, 32, 2, {INS_movntdq, INS_movntdq, INS_movntdq, INS_movntdq, INS_movntdq, INS_movntdq, INS_movntdq, INS_movntdq, INS_movntps, INS_movntpd}, HW_Category_MemoryStore, HW_Flag_NoRMWSemantics) HARDWARE_INTRINSIC(AVX_Subtract, "Subtract", AVX, -1, 32, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_subps, INS_subpd}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) HARDWARE_INTRINSIC(AVX_UnpackHigh, "UnpackHigh", AVX, -1, 32, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_unpckhps, INS_unpckhpd}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) HARDWARE_INTRINSIC(AVX_UnpackLow, "UnpackLow", AVX, -1, 32, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_unpcklps, INS_unpcklpd}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) @@ -348,7 +348,7 @@ HARDWARE_INTRINSIC(AVX_Xor, "Xor", // AVX2 Intrinsics HARDWARE_INTRINSIC(AVX2_IsSupported, "get_IsSupported", AVX2, -1, 0, 0, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_IsSupportedProperty, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(AVX2_Abs, "Abs", AVX2, -1, 32, 1, {INS_pabsb, INS_pabsb, INS_pabsw, INS_pabsw, INS_pabsd, INS_pabsd, INS_paddq, INS_paddq, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AVX2_Abs, "Abs", AVX2, -1, 32, 1, {INS_pabsb, INS_pabsb, INS_pabsw, INS_pabsw, INS_pabsd, INS_pabsd, INS_paddq, INS_paddq, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoRMWSemantics) HARDWARE_INTRINSIC(AVX2_Add, "Add", AVX2, -1, 32, 2, {INS_paddb, INS_paddb, INS_paddw, INS_paddw, INS_paddd, INS_paddd, INS_paddq, INS_paddq, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_Commutative) HARDWARE_INTRINSIC(AVX2_AddSaturate, "AddSaturate", AVX2, -1, 32, 2, {INS_paddsb, INS_paddusb, INS_paddsw, INS_paddusw, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_Commutative) HARDWARE_INTRINSIC(AVX2_And, "And", AVX2, -1, 32, 2, {INS_pand, INS_pand, INS_pand, INS_pand, INS_pand, INS_pand, INS_pand, INS_pand, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_Commutative) @@ -361,7 +361,7 @@ HARDWARE_INTRINSIC(AVX2_HorizontalAdd, "Horizontal 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_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_NoFlag) +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_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_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) @@ -391,14 +391,14 @@ HARDWARE_INTRINSIC(FMA_IsSupported, "get_IsSupp // LZCNT Intrinsics HARDWARE_INTRINSIC(LZCNT_IsSupported, "get_IsSupported", LZCNT, -1, 0, 0, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_IsSupportedProperty, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(LZCNT_LeadingZeroCount, "LeadingZeroCount", LZCNT, -1, 0, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_lzcnt, INS_invalid, INS_lzcnt, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoFloatingPointUsed) +HARDWARE_INTRINSIC(LZCNT_LeadingZeroCount, "LeadingZeroCount", LZCNT, -1, 0, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_lzcnt, INS_invalid, INS_lzcnt, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoFloatingPointUsed|HW_Flag_NoRMWSemantics) // PCLMULQDQ Intrinsics HARDWARE_INTRINSIC(PCLMULQDQ_IsSupported, "get_IsSupported", PCLMULQDQ, -1, 0, 0, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_IsSupportedProperty, HW_Flag_NoFlag) // POPCNT Intrinsics HARDWARE_INTRINSIC(POPCNT_IsSupported, "get_IsSupported", POPCNT, -1, 0, 0, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_IsSupportedProperty, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(POPCNT_PopCount, "PopCount", POPCNT, -1, 0, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_popcnt, INS_invalid, INS_popcnt, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoFloatingPointUsed) +HARDWARE_INTRINSIC(POPCNT_PopCount, "PopCount", POPCNT, -1, 0, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_popcnt, INS_invalid, INS_popcnt, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoFloatingPointUsed|HW_Flag_NoRMWSemantics) #endif // FEATURE_HW_INTRINSIC #undef HARDWARE_INTRINSIC diff --git a/src/jit/lsraxarch.cpp b/src/jit/lsraxarch.cpp index e5a74fdf8408..d60d21359371 100644 --- a/src/jit/lsraxarch.cpp +++ b/src/jit/lsraxarch.cpp @@ -2253,14 +2253,18 @@ void LinearScan::BuildSIMD(GenTreeSIMD* simdTree) void LinearScan::BuildHWIntrinsic(GenTreeHWIntrinsic* intrinsicTree) { - TreeNodeInfo* info = currentNodeInfo; - NamedIntrinsic intrinsicID = intrinsicTree->gtHWIntrinsicId; - InstructionSet isa = Compiler::isaOfHWIntrinsic(intrinsicID); - int numArgs = Compiler::numArgsOfHWIntrinsic(intrinsicID); + TreeNodeInfo* info = currentNodeInfo; + NamedIntrinsic intrinsicID = intrinsicTree->gtHWIntrinsicId; + InstructionSet isa = Compiler::isaOfHWIntrinsic(intrinsicID); + HWIntrinsicCategory category = Compiler::categoryOfHWIntrinsic(intrinsicID); + HWIntrinsicFlag flags = Compiler::flagsOfHWIntrinsic(intrinsicID); + int numArgs = Compiler::numArgsOfHWIntrinsic(intrinsicID); + if (isa == InstructionSet_AVX || isa == InstructionSet_AVX2) { SetContainsAVXFlags(true, 32); } + GenTree* op1 = intrinsicTree->gtOp.gtOp1; GenTree* op2 = intrinsicTree->gtOp.gtOp2; info->srcCount = 0; @@ -2285,8 +2289,7 @@ void LinearScan::BuildHWIntrinsic(GenTreeHWIntrinsic* intrinsicTree) info->srcCount += GetOperandInfo(op2); } - if (Compiler::categoryOfHWIntrinsic(intrinsicID) == HW_Category_IMM && - (Compiler::flagsOfHWIntrinsic(intrinsicID) & HW_Flag_NoJmpTableIMM) == 0) + if ((category == HW_Category_IMM) && ((flags & HW_Flag_NoJmpTableIMM) == 0)) { GenTree* lastOp = Compiler::lastOpOfHWIntrinsic(intrinsicTree, numArgs); assert(lastOp != nullptr); @@ -2303,6 +2306,32 @@ void LinearScan::BuildHWIntrinsic(GenTreeHWIntrinsic* intrinsicTree) } } + if (!compiler->canUseVexEncoding()) + { + // On machines without VEX support, we sometimes have to inject an intermediate + // `movaps targetReg, op1Reg` in order to maintain the correct behavior. This + // becomes a problem if `op2Reg == targetReg` since that means we will overwrite + // op2. In order to resolve this, we currently mark the second operand as delay free. + + if ((flags & HW_Flag_NoRMWSemantics) == 0) + { + assert(category != HW_Category_MemoryLoad); + assert(category != HW_Category_MemoryStore); + + assert((flags & HW_Flag_NoCodeGen) == 0); + + assert(numArgs != 0); + assert(numArgs != 1); + + if (info->srcCount >= 2) + { + LocationInfoListNode* op2Info = useList.Begin()->Next(); + op2Info->info.isDelayFree = true; + info->hasDelayFreeSrc = true; + } + } + } + switch (intrinsicID) { case NI_SSE_CompareEqualOrderedScalar: diff --git a/src/jit/namedintrinsiclist.h b/src/jit/namedintrinsiclist.h index cf739328c245..7ad997ead71f 100644 --- a/src/jit/namedintrinsiclist.h +++ b/src/jit/namedintrinsiclist.h @@ -88,6 +88,10 @@ enum HWIntrinsicFlag : unsigned int // NoJmpTable IMM // the imm intrinsic does not need jumptable fallback when it gets non-const argument HW_Flag_NoJmpTableIMM = 0x2000, + + // No Read/Modify/Write Semantics + // the intrinsic does not have read/modify/write semantics and doesn't need + HW_Flag_NoRMWSemantics = 0x4000, }; inline HWIntrinsicFlag operator|(HWIntrinsicFlag c1, HWIntrinsicFlag c2)