diff --git a/src/coreclr/src/jit/codegenarm64.cpp b/src/coreclr/src/jit/codegenarm64.cpp index 4970dbd6261d39..f423eae3cac1be 100644 --- a/src/coreclr/src/jit/codegenarm64.cpp +++ b/src/coreclr/src/jit/codegenarm64.cpp @@ -7799,6 +7799,52 @@ void CodeGen::genArm64EmitterUnitTests() theEmitter->emitIns_R_R(INS_faddp, EA_8BYTE, REG_V0, REG_V1, INS_OPTS_2S); theEmitter->emitIns_R_R(INS_faddp, EA_16BYTE, REG_V2, REG_V3, INS_OPTS_2D); + // fcmeq Vd, Vn, #0.0 + theEmitter->emitIns_R_R(INS_fcmeq, EA_4BYTE, REG_V0, REG_V1); // scalar 4BYTE + theEmitter->emitIns_R_R(INS_fcmeq, EA_8BYTE, REG_V2, REG_V3); // scalar 8BYTE + + // fcmge Vd, Vn, #0.0 + theEmitter->emitIns_R_R(INS_fcmge, EA_4BYTE, REG_V0, REG_V1); // scalar 4BYTE + theEmitter->emitIns_R_R(INS_fcmge, EA_8BYTE, REG_V2, REG_V3); // scalar 8BYTE + + // fcmgt Vd, Vn, #0.0 + theEmitter->emitIns_R_R(INS_fcmgt, EA_4BYTE, REG_V0, REG_V1); // scalar 4BYTE + theEmitter->emitIns_R_R(INS_fcmgt, EA_8BYTE, REG_V2, REG_V3); // scalar 8BYTE + + // fcmle Vd, Vn, #0.0 + theEmitter->emitIns_R_R(INS_fcmle, EA_4BYTE, REG_V0, REG_V1); // scalar 4BYTE + theEmitter->emitIns_R_R(INS_fcmle, EA_8BYTE, REG_V2, REG_V3); // scalar 8BYTE + + // fcmlt Vd, Vn, #0.0 + theEmitter->emitIns_R_R(INS_fcmlt, EA_4BYTE, REG_V0, REG_V1); // scalar 4BYTE + theEmitter->emitIns_R_R(INS_fcmlt, EA_8BYTE, REG_V2, REG_V3); // scalar 8BYTE + + // frecpe scalar + theEmitter->emitIns_R_R(INS_frecpe, EA_4BYTE, REG_V0, REG_V1); // scalar 4BYTE + theEmitter->emitIns_R_R(INS_frecpe, EA_8BYTE, REG_V2, REG_V3); // scalar 8BYTE + theEmitter->emitIns_R_R(INS_frecpe, EA_8BYTE, REG_V4, REG_V5, INS_OPTS_2S); + theEmitter->emitIns_R_R(INS_frecpe, EA_16BYTE, REG_V6, REG_V7, INS_OPTS_4S); + theEmitter->emitIns_R_R(INS_frecpe, EA_16BYTE, REG_V8, REG_V9, INS_OPTS_2D); + + // frecpx scalar + theEmitter->emitIns_R_R(INS_frecpx, EA_4BYTE, REG_V0, REG_V1); + theEmitter->emitIns_R_R(INS_frecpx, EA_8BYTE, REG_V2, REG_V3); + + // frsqrte + theEmitter->emitIns_R_R(INS_frsqrte, EA_4BYTE, REG_V0, REG_V1); // scalar 4BYTE + theEmitter->emitIns_R_R(INS_frsqrte, EA_8BYTE, REG_V2, REG_V3); // scalar 8BYTE + theEmitter->emitIns_R_R(INS_frsqrte, EA_8BYTE, REG_V4, REG_V5, INS_OPTS_2S); + theEmitter->emitIns_R_R(INS_frsqrte, EA_16BYTE, REG_V6, REG_V7, INS_OPTS_4S); + theEmitter->emitIns_R_R(INS_frsqrte, EA_16BYTE, REG_V8, REG_V9, INS_OPTS_2D); + + // urecpe vector + theEmitter->emitIns_R_R(INS_urecpe, EA_8BYTE, REG_V0, REG_V1, INS_OPTS_2S); + theEmitter->emitIns_R_R(INS_urecpe, EA_16BYTE, REG_V2, REG_V3, INS_OPTS_4S); + + // ursqrte vector + theEmitter->emitIns_R_R(INS_ursqrte, EA_8BYTE, REG_V0, REG_V1, INS_OPTS_2S); + theEmitter->emitIns_R_R(INS_ursqrte, EA_16BYTE, REG_V2, REG_V3, INS_OPTS_4S); + // INS_fcvtl theEmitter->emitIns_R_R(INS_fcvtl, EA_4BYTE, REG_V0, REG_V1); @@ -7965,6 +8011,20 @@ void CodeGen::genArm64EmitterUnitTests() theEmitter->emitIns_R_R_R(INS_fabd, EA_16BYTE, REG_V9, REG_V10, REG_V11, INS_OPTS_4S); theEmitter->emitIns_R_R_R(INS_fabd, EA_16BYTE, REG_V12, REG_V13, REG_V14, INS_OPTS_2D); + // frecps + theEmitter->emitIns_R_R_R(INS_frecps, EA_4BYTE, REG_V0, REG_V1, REG_V2); // scalar 4BYTE + theEmitter->emitIns_R_R_R(INS_frecps, EA_8BYTE, REG_V3, REG_V4, REG_V5); // scalar 8BYTE + theEmitter->emitIns_R_R_R(INS_frecps, EA_8BYTE, REG_V6, REG_V7, REG_V8, INS_OPTS_2S); + theEmitter->emitIns_R_R_R(INS_frecps, EA_16BYTE, REG_V9, REG_V10, REG_V11, INS_OPTS_4S); + theEmitter->emitIns_R_R_R(INS_frecps, EA_16BYTE, REG_V12, REG_V13, REG_V14, INS_OPTS_2D); + + // frsqrts + theEmitter->emitIns_R_R_R(INS_frsqrts, EA_4BYTE, REG_V0, REG_V1, REG_V2); // scalar 4BYTE + theEmitter->emitIns_R_R_R(INS_frsqrts, EA_8BYTE, REG_V3, REG_V4, REG_V5); // scalar 8BYTE + theEmitter->emitIns_R_R_R(INS_frsqrts, EA_8BYTE, REG_V6, REG_V7, REG_V8, INS_OPTS_2S); + theEmitter->emitIns_R_R_R(INS_frsqrts, EA_16BYTE, REG_V9, REG_V10, REG_V11, INS_OPTS_4S); + theEmitter->emitIns_R_R_R(INS_frsqrts, EA_16BYTE, REG_V12, REG_V13, REG_V14, INS_OPTS_2D); + genDefineTempLabel(genCreateTempLabel()); theEmitter->emitIns_R_R_R(INS_fmul, EA_4BYTE, REG_V0, REG_V1, REG_V2); // scalar 4BYTE diff --git a/src/coreclr/src/jit/emitarm64.cpp b/src/coreclr/src/jit/emitarm64.cpp index e31a9ab43b5bc4..88e6a6b33a9e3c 100644 --- a/src/coreclr/src/jit/emitarm64.cpp +++ b/src/coreclr/src/jit/emitarm64.cpp @@ -4504,27 +4504,30 @@ void emitter::emitIns_R_R( case INS_fcmgt: case INS_fcmle: case INS_fcmlt: + case INS_frecpe: + case INS_frsqrte: assert(isVectorRegister(reg1)); assert(isVectorRegister(reg2)); - if (isValidVectorDatasize(size)) + if (insOptsAnyArrangement(opt)) { // Vector operation - assert(insOptsAnyArrangement(opt)); + assert(isValidVectorDatasize(size)); assert(isValidArrangement(size, opt)); elemsize = optGetElemsize(opt); - assert((elemsize == EA_8BYTE) || (elemsize == EA_4BYTE)); // Only Double/Float supported - assert(opt != INS_OPTS_1D); // Reserved encoding + assert(isValidVectorElemsizeFloat(elemsize)); // Only Double/Float supported + assert(opt != INS_OPTS_1D); // Reserved encoding fmt = IF_DV_2A; } else { - NYI("Untested"); // Scalar operation - assert((size == EA_8BYTE) || (size == EA_4BYTE)); // Only Double/Float supported + assert(isValidScalarDatasize(size)); // Only Double/Float supported + assert(insOptsNone(opt)); fmt = IF_DV_2G; } break; + case INS_aesd: case INS_aese: case INS_aesmc: @@ -4586,6 +4589,25 @@ void emitter::emitIns_R_R( fmt = IF_LS_2D; break; + case INS_urecpe: + case INS_ursqrte: + assert(isVectorRegister(reg1)); + assert(isVectorRegister(reg2)); + assert(isValidVectorDatasize(size)); + assert(isValidArrangement(size, opt)); + elemsize = optGetElemsize(opt); + assert(elemsize == EA_4BYTE); + fmt = IF_DV_2A; + break; + + case INS_frecpx: + assert(isVectorRegister(reg1)); + assert(isVectorRegister(reg2)); + assert(isValidScalarDatasize(size)); + assert(insOptsNone(opt)); + fmt = IF_DV_2G; + break; + default: unreached(); break; @@ -5532,6 +5554,8 @@ void emitter::emitIns_R_R_R( case INS_fcmeq: case INS_fcmge: case INS_fcmgt: + case INS_frecps: + case INS_frsqrts: assert(isVectorRegister(reg1)); assert(isVectorRegister(reg2)); assert(isVectorRegister(reg3)); @@ -12151,7 +12175,16 @@ void emitter::emitDispIns( case IF_DV_2L: // DV_2L ........XX...... ......nnnnnddddd Vd Vn (abs, neg - scalar) elemsize = id->idOpSize(); emitDispReg(id->idReg1(), elemsize, true); - emitDispReg(id->idReg2(), elemsize, false); + if ((ins == INS_fcmeq) || (ins == INS_fcmge) || (ins == INS_fcmgt) || (ins == INS_fcmle) || + (ins == INS_fcmlt)) + { + emitDispReg(id->idReg2(), elemsize, true); + emitDispImm(0, false); + } + else + { + emitDispReg(id->idReg2(), elemsize, false); + } break; case IF_DV_2H: // DV_2H X........X...... ......nnnnnddddd Rd Vn (fmov, fcvtXX - to general) @@ -13516,6 +13549,10 @@ emitter::insExecutionCharacteristics emitter::getInsExecutionCharacteristics(ins case INS_fcmgt: case INS_fcmle: case INS_fcmlt: + case INS_frecpe: + case INS_frsqrte: + case INS_urecpe: + case INS_ursqrte: result.insThroughput = PERFSCORE_THROUGHPUT_2X; result.insLatency = PERFSCORE_LATENCY_2C; break; @@ -13580,6 +13617,13 @@ emitter::insExecutionCharacteristics emitter::getInsExecutionCharacteristics(ins result.insLatency = PERFSCORE_LATENCY_4C; break; + case INS_frecpe: + case INS_frecpx: + case INS_frsqrte: + result.insThroughput = PERFSCORE_THROUGHPUT_2X; + result.insLatency = PERFSCORE_LATENCY_4C; + break; + case INS_fsqrt: if (id->idOpSize() == EA_8BYTE) { @@ -13629,6 +13673,8 @@ emitter::insExecutionCharacteristics emitter::getInsExecutionCharacteristics(ins case INS_fmulx: case INS_fmla: case INS_fmls: + case INS_frecps: + case INS_frsqrts: result.insThroughput = PERFSCORE_THROUGHPUT_2X; result.insLatency = PERFSCORE_LATENCY_4C; break; @@ -13718,6 +13764,8 @@ emitter::insExecutionCharacteristics emitter::getInsExecutionCharacteristics(ins case INS_fmul: case INS_fmulx: case INS_fnmul: + case INS_frecps: + case INS_frsqrts: result.insThroughput = PERFSCORE_THROUGHPUT_2X; result.insLatency = PERFSCORE_LATENCY_4C; break; diff --git a/src/coreclr/src/jit/hwintrinsiclistarm64.h b/src/coreclr/src/jit/hwintrinsiclistarm64.h index 8be27939f4e13c..96ef1ab72647eb 100644 --- a/src/coreclr/src/jit/hwintrinsiclistarm64.h +++ b/src/coreclr/src/jit/hwintrinsiclistarm64.h @@ -54,7 +54,8 @@ HARDWARE_INTRINSIC(AdvSimd, AbsoluteCompareGreaterThan, - HARDWARE_INTRINSIC(AdvSimd, AbsoluteCompareGreaterThanOrEqual, -1, -1, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_facge, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_UnfixedSIMDSize) HARDWARE_INTRINSIC(AdvSimd, AbsoluteCompareLessThan, -1, -1, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_facgt, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_UnfixedSIMDSize|HW_Flag_SpecialCodeGen) HARDWARE_INTRINSIC(AdvSimd, AbsoluteCompareLessThanOrEqual, -1, -1, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_facge, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_UnfixedSIMDSize|HW_Flag_SpecialCodeGen) -HARDWARE_INTRINSIC(AdvSimd, AbsoluteDifference, -1, -1, 2, {INS_sabd, INS_uabd, INS_sabd, INS_uabd, INS_sabd, INS_uabd, INS_invalid, INS_invalid, INS_fabd, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_UnfixedSIMDSize) +HARDWARE_INTRINSIC(AdvSimd, AbsoluteDifference, -1, -1, 2, {INS_sabd, INS_uabd, INS_sabd, INS_uabd, INS_sabd, INS_uabd, INS_invalid, INS_invalid, INS_fabd, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_UnfixedSIMDSize|HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(AdvSimd, AbsoluteDifferenceAdd, -1, -1, 3, {INS_saba, INS_uaba, INS_saba, INS_uaba, INS_saba, INS_uaba, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_UnfixedSIMDSize) HARDWARE_INTRINSIC(AdvSimd, Add, -1, -1, 2, {INS_add, INS_add, INS_add, INS_add, INS_add, INS_add, INS_add, INS_add, INS_fadd, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_Commutative|HW_Flag_UnfixedSIMDSize) HARDWARE_INTRINSIC(AdvSimd, AddPairwise, -1, 8, 2, {INS_addp, INS_addp, INS_addp, INS_addp, INS_addp, INS_addp, INS_invalid, INS_invalid, INS_faddp, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoContainment) HARDWARE_INTRINSIC(AdvSimd, AddScalar, -1, 8, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_add, INS_add, INS_fadd, INS_fadd}, HW_Category_SIMDScalar, HW_Flag_NoContainment|HW_Flag_Commutative) @@ -95,7 +96,12 @@ HARDWARE_INTRINSIC(AdvSimd, NegateScalar, - HARDWARE_INTRINSIC(AdvSimd, Not, -1, -1, 1, {INS_mvn, INS_mvn, INS_mvn, INS_mvn, INS_mvn, INS_mvn, INS_mvn, INS_mvn, INS_mvn, INS_mvn}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_UnfixedSIMDSize) HARDWARE_INTRINSIC(AdvSimd, Or, -1, -1, 2, {INS_orr, INS_orr, INS_orr, INS_orr, INS_orr, INS_orr, INS_orr, INS_orr, INS_orr, INS_orr}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_UnfixedSIMDSize|HW_Flag_Commutative) HARDWARE_INTRINSIC(AdvSimd, OrNot, -1, -1, 2, {INS_orn, INS_orn, INS_orn, INS_orn, INS_orn, INS_orn, INS_orn, INS_orn, INS_orn, INS_orn}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_UnfixedSIMDSize) +HARDWARE_INTRINSIC(AdvSimd, PolynomialMultiply, -1, -1, 2, {INS_pmul, INS_pmul, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_UnfixedSIMDSize|HW_Flag_Commutative) HARDWARE_INTRINSIC(AdvSimd, PopCount, -1, -1, 1, {INS_cnt, INS_cnt, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_UnfixedSIMDSize) +HARDWARE_INTRINSIC(AdvSimd, ReciprocalEstimate, -1, -1, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_urecpe, INS_invalid, INS_invalid, INS_frecpe, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_UnfixedSIMDSize) +HARDWARE_INTRINSIC(AdvSimd, ReciprocalSquareRootEstimate, -1, -1, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_ursqrte, INS_invalid, INS_invalid, INS_frsqrte, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_UnfixedSIMDSize) +HARDWARE_INTRINSIC(AdvSimd, ReciprocalSquareRootStep, -1, -1, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_frsqrts, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_UnfixedSIMDSize|HW_Flag_Commutative) +HARDWARE_INTRINSIC(AdvSimd, ReciprocalStep, -1, -1, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_frecps, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_UnfixedSIMDSize|HW_Flag_Commutative) HARDWARE_INTRINSIC(AdvSimd, SqrtScalar, -1, 8, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_fsqrt, INS_fsqrt}, HW_Category_SIMDScalar, HW_Flag_NoContainment) HARDWARE_INTRINSIC(AdvSimd, Subtract, -1, -1, 2, {INS_sub, INS_sub, INS_sub, INS_sub, INS_sub, INS_sub, INS_sub, INS_sub, INS_fsub, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_UnfixedSIMDSize) HARDWARE_INTRINSIC(AdvSimd, SubtractScalar, -1, 8, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sub, INS_sub, INS_fsub, INS_fsub}, HW_Category_SIMDScalar, HW_Flag_NoContainment) @@ -156,8 +162,19 @@ HARDWARE_INTRINSIC(AdvSimd_Arm64, MinPairwise, - HARDWARE_INTRINSIC(AdvSimd_Arm64, MinPairwiseScalar, -1, -1, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_fminp, INS_fminp}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_BaseTypeFromFirstArg|HW_Flag_UnfixedSIMDSize) HARDWARE_INTRINSIC(AdvSimd_Arm64, MinScalar, -1, 8, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_fmin, INS_fmin}, HW_Category_SIMDScalar, HW_Flag_NoContainment|HW_Flag_Commutative) HARDWARE_INTRINSIC(AdvSimd_Arm64, Multiply, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_fmul}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_Commutative) +HARDWARE_INTRINSIC(AdvSimd_Arm64, MultiplyExtended, -1, -1, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_fmulx, INS_fmulx}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_UnfixedSIMDSize|HW_Flag_Commutative) +HARDWARE_INTRINSIC(AdvSimd_Arm64, MultiplyExtendedScalar, -1, 8, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_fmulx, INS_fmulx}, HW_Category_SIMDScalar, HW_Flag_NoContainment|HW_Flag_Commutative) HARDWARE_INTRINSIC(AdvSimd_Arm64, Negate, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_neg, INS_invalid, INS_invalid, INS_fneg}, HW_Category_SimpleSIMD, HW_Flag_NoContainment) HARDWARE_INTRINSIC(AdvSimd_Arm64, NegateScalar, -1, 8, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_neg, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_NoContainment) +HARDWARE_INTRINSIC(AdvSimd_Arm64, ReciprocalEstimate, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_frecpe}, HW_Category_SimpleSIMD, HW_Flag_NoContainment) +HARDWARE_INTRINSIC(AdvSimd_Arm64, ReciprocalEstimateScalar, -1, 8, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_frecpe, INS_frecpe}, HW_Category_SIMDScalar, HW_Flag_NoContainment) +HARDWARE_INTRINSIC(AdvSimd_Arm64, ReciprocalExponentScalar, -1, 8, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_frecpx, INS_frecpx}, HW_Category_SIMDScalar, HW_Flag_NoContainment) +HARDWARE_INTRINSIC(AdvSimd_Arm64, ReciprocalSquareRootEstimate, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_frsqrte}, HW_Category_SimpleSIMD, HW_Flag_NoContainment) +HARDWARE_INTRINSIC(AdvSimd_Arm64, ReciprocalSquareRootEstimateScalar, -1, 8, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_frsqrte, INS_frsqrte}, HW_Category_SIMDScalar, HW_Flag_NoContainment) +HARDWARE_INTRINSIC(AdvSimd_Arm64, ReciprocalSquareRootStep, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_frsqrts}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_Commutative) +HARDWARE_INTRINSIC(AdvSimd_Arm64, ReciprocalSquareRootStepScalar, -1, 8, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_frsqrts, INS_frsqrts}, HW_Category_SIMDScalar, HW_Flag_NoContainment|HW_Flag_Commutative) +HARDWARE_INTRINSIC(AdvSimd_Arm64, ReciprocalStep, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_frecps}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_Commutative) +HARDWARE_INTRINSIC(AdvSimd_Arm64, ReciprocalStepScalar, -1, 8, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_frecps, INS_frecps}, HW_Category_SIMDScalar, HW_Flag_NoContainment|HW_Flag_Commutative) HARDWARE_INTRINSIC(AdvSimd_Arm64, ReverseElementBits, -1, -1, 1, {INS_rbit, INS_rbit, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_UnfixedSIMDSize) HARDWARE_INTRINSIC(AdvSimd_Arm64, Sqrt, -1, -1, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_fsqrt, INS_fsqrt}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_UnfixedSIMDSize) HARDWARE_INTRINSIC(AdvSimd_Arm64, Subtract, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_fsub}, HW_Category_SimpleSIMD, HW_Flag_NoContainment) diff --git a/src/coreclr/src/jit/instrsarm64.h b/src/coreclr/src/jit/instrsarm64.h index 6958660ac68a32..d9c8dfff9d2caa 100644 --- a/src/coreclr/src/jit/instrsarm64.h +++ b/src/coreclr/src/jit/instrsarm64.h @@ -594,6 +594,16 @@ INST2(facgt, "facgt", 0, 0, IF_EN2G, 0x2EA0EC00, 0x7EA0EC00) // facgt Vd,Vn,Vm DV_3B 0Q1011101X1mmmmm 111011nnnnnddddd 2EA0 EC00 Vd,Vn,Vm (vector) // facgt Vd,Vn,Vm DV_3D 011111101X1mmmmm 111011nnnnnddddd 7EA0 EC00 Vd,Vn,Vm (scalar) +INST2(frecps, "frecps", 0, 0, IF_EN2G, 0x0E20FC00, 0x5E20FC00) + // C7.2.138 FRECPS + // frecps Vd,Vn,Vm DV_3B 0Q0011100X1mmmmm 111111nnnnnddddd 0E20 FC00 Vd,Vn,Vm (vector) + // frecps Vd,Vn,Vm DV_3D 010111100X1mmmmm 111111nnnnnddddd 5E20 FC00 Vd,Vn,Vm (scalar) + +INST2(frsqrts, "frsqrts",0, 0, IF_EN2G, 0x0EA0FC00, 0x5EA0FC00) + // C7.2.163 FRSQRTS + // frsqrts Vd,Vn,Vm DV_3B 0Q0011101X1mmmmm 111111nnnnnddddd 0EA0 FC00 Vd,Vn,Vm (vector) + // frsqrts Vd,Vn,Vm DV_3D 010111101X1mmmmm 111111nnnnnddddd 5EA0 FC00 Vd,Vn,Vm (scalar) + // enum name FP LD/ST DV_2K DV_1C INST2(fcmp, "fcmp", 0, 0, IF_EN2I, 0x1E202000, 0x1E202008) // fcmp Vn,Vm DV_2K 000111100X1mmmmm 001000nnnnn00000 1E20 2000 Vn Vm @@ -620,9 +630,9 @@ INST2(fneg, "fneg", 0, 0, IF_EN2J, 0x2EA0F800, 0x1E214000) // fneg Vd,Vn DV_2A 0Q1011101X100000 111110nnnnnddddd 2EA0 F800 Vd,Vn (vector) // fneg Vd,Vn DV_2G 000111100X100001 010000nnnnnddddd 1E21 4000 Vd,Vn (scalar) -INST2(fsqrt, "fsqrt", 0, 0, IF_EN2J, 0x2EA1F800, 0x1E21C000) - // fsqrt Vd,Vn DV_2A 0Q1011101X100001 111110nnnnnddddd 2EA1 F800 Vd,Vn (vector) - // fsqrt Vd,Vn DV_2G 000111100X100001 110000nnnnnddddd 1E21 C000 Vd,Vn (scalar) +INST2(frecpe, "frecpe", 0, 0, IF_EN2J, 0x0EA1D800, 0x5EA1D800) + // frecpe Vd,Vn DV_2A 0Q0011101X100001 110110nnnnnddddd 0EA1 D800 Vd,Vn (vector) + // frecpe Vd,Vn DV_2G 010111101X100001 110110nnnnnddddd 5EA1 D800 Vd,Vn (scalar) INST2(frintn, "frintn", 0, 0, IF_EN2J, 0x0E218800, 0x1E244000) // frintn Vd,Vn DV_2A 0Q0011100X100001 100010nnnnnddddd 0E21 8800 Vd,Vn (vector) @@ -652,6 +662,17 @@ INST2(frinti, "frinti", 0, 0, IF_EN2J, 0x2EA19800, 0x1E27C000) // frinti Vd,Vn DV_2A 0Q1011101X100001 100110nnnnnddddd 2EA1 9800 Vd,Vn (vector) // frinti Vd,Vn DV_2G 000111100X100111 110000nnnnnddddd 1E27 C000 Vd,Vn (scalar) +INST2(frsqrte, "frsqrte",0, 0, IF_EN2J, 0x2EA1D800, 0x7EA1D800) + // C7.2.162 FRSQRTE + // frsqrte Vd,Vn DV_2A 0Q1011101X100001 110110nnnnnddddd 2EA1 D800 Vd,Vn (vector) + // frsqrte Vd,Vn DV_2G 011111101X100001 110110nnnnnddddd 7EA1 D800 Vd,Vn (scalar) + +INST2(fsqrt, "fsqrt", 0, 0, IF_EN2J, 0x2EA1F800, 0x1E21C000) + // C7.2.164 FSQRT (vector) + // fsqrt Vd,Vn DV_2A 0Q1011101X100001 111110nnnnnddddd 2EA1 F800 Vd,Vn (vector) + // C7.2.165 FSQRT (scalar) + // fsqrt Vd,Vn DV_2G 000111100X100001 110000nnnnnddddd 1E21 C000 Vd,Vn (scalar) + // enum name FP LD/ST DV_2M DV_2L INST2(abs, "abs", 0, 0, IF_EN2K, 0x0E20B800, 0x5E20B800) // abs Vd,Vn DV_2M 0Q001110XX100000 101110nnnnnddddd 0E20 B800 Vd,Vn (vector) @@ -1321,6 +1342,14 @@ INST1(movi, "movi", 0, 0, IF_DV_1B, 0x0F000400) INST1(mvni, "mvni", 0, 0, IF_DV_1B, 0x2F000400) // mvni Vd,imm8 DV_1B 0Q10111100000iii cmod01iiiiiddddd 2F00 0400 Vd imm8 (immediate vector) +INST1(urecpe, "urecpe", 0, 0, IF_DV_2A, 0x0EA1C800) + // C7.2.372 URECPE + // urecpe Vd,Vn DV_2A 0Q0011101X100001 110010nnnnnddddd 0EA1 C800 Vd,Vn (vector) + +INST1(ursqrte, "ursqrte",0, 0, IF_DV_2A, 0x2EA1C800) + // C7.2.376 URSQRTE + // ursqrte Vd,Vn DV_2A 0Q1011101X100001 110010nnnnnddddd 2EA1 C800 Vd,Vn (vector) + INST1(bsl, "bsl", 0, 0, IF_DV_3C, 0x2E601C00) // bsl Vd,Vn,Vm DV_3C 0Q101110011mmmmm 000111nnnnnddddd 2E60 1C00 Vd,Vn,Vm @@ -1462,6 +1491,10 @@ INST1(fcvtn, "fcvtn", 0, 0, IF_DV_2G, 0x0E216800) INST1(fcvtn2, "fcvtn2", 0, 0, IF_DV_2G, 0x4E216800) // fcvtn2 Vd,Vn DV_2G 040011100X100001 011010nnnnnddddd 4E21 6800 Vd,Vn (scalar) +INST1(frecpx, "frecpx", 0, 0, IF_DV_2G, 0x5EA1F800) + // C7.2.139 FRECPX + // frecpx Vd,Vn DV_2G 010111101X100001 111110nnnnnddddd 5EA1 F800 Vd,Vn (scalar) + INST1(shll, "shll", 0, 0, IF_DV_2M, 0x2F00A400) // shll Vd,Vn,imm DV_2M 0Q101110XX100001 001110nnnnnddddd 2E21 3800 Vd,Vn, {8/16/32} diff --git a/src/coreclr/src/jit/lsraarm64.cpp b/src/coreclr/src/jit/lsraarm64.cpp index 6a695a1185a0a0..116ccace18b2a6 100644 --- a/src/coreclr/src/jit/lsraarm64.cpp +++ b/src/coreclr/src/jit/lsraarm64.cpp @@ -1133,6 +1133,7 @@ int LinearScan::BuildHWIntrinsic(GenTreeHWIntrinsic* intrinsicTree) } break; + case NI_AdvSimd_AbsoluteDifferenceAdd: case NI_AdvSimd_FusedMultiplyAdd: case NI_AdvSimd_FusedMultiplySubtract: case NI_AdvSimd_Arm64_FusedMultiplyAdd: diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/AdvSimd.Arm64_r.csproj b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/AdvSimd.Arm64_r.csproj index 81252895be3669..98bcab7a7c5bc4 100644 --- a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/AdvSimd.Arm64_r.csproj +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/AdvSimd.Arm64_r.csproj @@ -160,9 +160,28 @@ + + + + + + + + + + + + + + + + + + + diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/AdvSimd.Arm64_ro.csproj b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/AdvSimd.Arm64_ro.csproj index 2e884b2462c107..0a58c29ec9ddea 100644 --- a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/AdvSimd.Arm64_ro.csproj +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/AdvSimd.Arm64_ro.csproj @@ -160,9 +160,28 @@ + + + + + + + + + + + + + + + + + + + diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/MultiplyExtended.Vector128.Double.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/MultiplyExtended.Vector128.Double.cs new file mode 100644 index 00000000000000..78c2629be4528e --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/MultiplyExtended.Vector128.Double.cs @@ -0,0 +1,530 @@ +// 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.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void MultiplyExtended_Vector128_Double() + { + var test = new SimpleBinaryOpTest__MultiplyExtended_Vector128_Double(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + 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__MultiplyExtended_Vector128_Double + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Double[] inArray1, Double[] inArray2, Double[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetDouble(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetDouble(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__MultiplyExtended_Vector128_Double testClass) + { + var result = AdvSimd.Arm64.MultiplyExtended(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__MultiplyExtended_Vector128_Double testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.Arm64.MultiplyExtended( + AdvSimd.LoadVector128((Double*)(pFld1)), + AdvSimd.LoadVector128((Double*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Double); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Double); + private static readonly int RetElementCount = Unsafe.SizeOf>() / 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 DataTable _dataTable; + + static SimpleBinaryOpTest__MultiplyExtended_Vector128_Double() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetDouble(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetDouble(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__MultiplyExtended_Vector128_Double() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetDouble(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetDouble(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetDouble(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetDouble(); } + _dataTable = new DataTable(_data1, _data2, new Double[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Arm64.MultiplyExtended( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Arm64.MultiplyExtended( + AdvSimd.LoadVector128((Double*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Double*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.MultiplyExtended), 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() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.MultiplyExtended), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Double*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Double*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Arm64.MultiplyExtended( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.Arm64.MultiplyExtended( + AdvSimd.LoadVector128((Double*)(pClsVar1)), + AdvSimd.LoadVector128((Double*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.Arm64.MultiplyExtended(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Double*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Double*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.Arm64.MultiplyExtended(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__MultiplyExtended_Vector128_Double(); + var result = AdvSimd.Arm64.MultiplyExtended(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__MultiplyExtended_Vector128_Double(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.Arm64.MultiplyExtended( + AdvSimd.LoadVector128((Double*)(pFld1)), + AdvSimd.LoadVector128((Double*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Arm64.MultiplyExtended(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.Arm64.MultiplyExtended( + AdvSimd.LoadVector128((Double*)(pFld1)), + AdvSimd.LoadVector128((Double*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.MultiplyExtended(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.MultiplyExtended( + AdvSimd.LoadVector128((Double*)(&test._fld1)), + AdvSimd.LoadVector128((Double*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + Double[] inArray1 = new Double[Op1ElementCount]; + Double[] inArray2 = new Double[Op2ElementCount]; + Double[] outArray = new Double[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, 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(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Double[] left, Double[] right, Double[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (BitConverter.DoubleToInt64Bits(Helpers.MultiplyExtended(left[i], right[i])) != BitConverter.DoubleToInt64Bits(result[i])) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.MultiplyExtended)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/MultiplyExtended.Vector128.Single.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/MultiplyExtended.Vector128.Single.cs new file mode 100644 index 00000000000000..76ed74019aa03e --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/MultiplyExtended.Vector128.Single.cs @@ -0,0 +1,530 @@ +// 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.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void MultiplyExtended_Vector128_Single() + { + var test = new SimpleBinaryOpTest__MultiplyExtended_Vector128_Single(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + 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__MultiplyExtended_Vector128_Single + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Single[] inArray1, Single[] inArray2, Single[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSingle(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSingle(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__MultiplyExtended_Vector128_Single testClass) + { + var result = AdvSimd.Arm64.MultiplyExtended(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__MultiplyExtended_Vector128_Single testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.Arm64.MultiplyExtended( + AdvSimd.LoadVector128((Single*)(pFld1)), + AdvSimd.LoadVector128((Single*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Single); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Single); + private static readonly int RetElementCount = Unsafe.SizeOf>() / 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 DataTable _dataTable; + + static SimpleBinaryOpTest__MultiplyExtended_Vector128_Single() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSingle(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSingle(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__MultiplyExtended_Vector128_Single() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSingle(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSingle(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSingle(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSingle(); } + _dataTable = new DataTable(_data1, _data2, new Single[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Arm64.MultiplyExtended( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Arm64.MultiplyExtended( + AdvSimd.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.MultiplyExtended), 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() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.MultiplyExtended), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Arm64.MultiplyExtended( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.Arm64.MultiplyExtended( + AdvSimd.LoadVector128((Single*)(pClsVar1)), + AdvSimd.LoadVector128((Single*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.Arm64.MultiplyExtended(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Single*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Single*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.Arm64.MultiplyExtended(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__MultiplyExtended_Vector128_Single(); + var result = AdvSimd.Arm64.MultiplyExtended(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__MultiplyExtended_Vector128_Single(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.Arm64.MultiplyExtended( + AdvSimd.LoadVector128((Single*)(pFld1)), + AdvSimd.LoadVector128((Single*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Arm64.MultiplyExtended(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.Arm64.MultiplyExtended( + AdvSimd.LoadVector128((Single*)(pFld1)), + AdvSimd.LoadVector128((Single*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.MultiplyExtended(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.MultiplyExtended( + AdvSimd.LoadVector128((Single*)(&test._fld1)), + AdvSimd.LoadVector128((Single*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + Single[] inArray1 = new Single[Op1ElementCount]; + Single[] inArray2 = new Single[Op2ElementCount]; + Single[] outArray = new Single[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, 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(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Single[] left, Single[] right, Single[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (BitConverter.SingleToInt32Bits(Helpers.MultiplyExtended(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.MultiplyExtended)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/MultiplyExtended.Vector64.Single.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/MultiplyExtended.Vector64.Single.cs new file mode 100644 index 00000000000000..97bd8770cba077 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/MultiplyExtended.Vector64.Single.cs @@ -0,0 +1,530 @@ +// 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.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void MultiplyExtended_Vector64_Single() + { + var test = new SimpleBinaryOpTest__MultiplyExtended_Vector64_Single(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + 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__MultiplyExtended_Vector64_Single + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Single[] inArray1, Single[] inArray2, Single[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSingle(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSingle(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__MultiplyExtended_Vector64_Single testClass) + { + var result = AdvSimd.Arm64.MultiplyExtended(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__MultiplyExtended_Vector64_Single testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.Arm64.MultiplyExtended( + AdvSimd.LoadVector64((Single*)(pFld1)), + AdvSimd.LoadVector64((Single*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Single); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Single); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Single); + + private static Single[] _data1 = new Single[Op1ElementCount]; + private static Single[] _data2 = new Single[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__MultiplyExtended_Vector64_Single() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSingle(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSingle(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__MultiplyExtended_Vector64_Single() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSingle(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSingle(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSingle(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSingle(); } + _dataTable = new DataTable(_data1, _data2, new Single[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Arm64.MultiplyExtended( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Arm64.MultiplyExtended( + AdvSimd.LoadVector64((Single*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Single*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.MultiplyExtended), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.MultiplyExtended), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Single*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Single*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Arm64.MultiplyExtended( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.Arm64.MultiplyExtended( + AdvSimd.LoadVector64((Single*)(pClsVar1)), + AdvSimd.LoadVector64((Single*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.Arm64.MultiplyExtended(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Single*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Single*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.Arm64.MultiplyExtended(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__MultiplyExtended_Vector64_Single(); + var result = AdvSimd.Arm64.MultiplyExtended(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__MultiplyExtended_Vector64_Single(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.Arm64.MultiplyExtended( + AdvSimd.LoadVector64((Single*)(pFld1)), + AdvSimd.LoadVector64((Single*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Arm64.MultiplyExtended(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.Arm64.MultiplyExtended( + AdvSimd.LoadVector64((Single*)(pFld1)), + AdvSimd.LoadVector64((Single*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.MultiplyExtended(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.MultiplyExtended( + AdvSimd.LoadVector64((Single*)(&test._fld1)), + AdvSimd.LoadVector64((Single*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + Single[] inArray1 = new Single[Op1ElementCount]; + Single[] inArray2 = new Single[Op2ElementCount]; + Single[] outArray = new Single[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, 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(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Single[] left, Single[] right, Single[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (BitConverter.SingleToInt32Bits(Helpers.MultiplyExtended(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.MultiplyExtended)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/MultiplyExtendedScalar.Vector64.Double.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/MultiplyExtendedScalar.Vector64.Double.cs new file mode 100644 index 00000000000000..3f69cd425bfc31 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/MultiplyExtendedScalar.Vector64.Double.cs @@ -0,0 +1,537 @@ +// 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.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void MultiplyExtendedScalar_Vector64_Double() + { + var test = new SimpleBinaryOpTest__MultiplyExtendedScalar_Vector64_Double(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + 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__MultiplyExtendedScalar_Vector64_Double + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Double[] inArray1, Double[] inArray2, Double[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetDouble(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetDouble(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__MultiplyExtendedScalar_Vector64_Double testClass) + { + var result = AdvSimd.Arm64.MultiplyExtendedScalar(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__MultiplyExtendedScalar_Vector64_Double testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.Arm64.MultiplyExtendedScalar( + AdvSimd.LoadVector64((Double*)(pFld1)), + AdvSimd.LoadVector64((Double*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Double); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Double); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Double); + + private static Double[] _data1 = new Double[Op1ElementCount]; + private static Double[] _data2 = new Double[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__MultiplyExtendedScalar_Vector64_Double() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetDouble(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetDouble(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__MultiplyExtendedScalar_Vector64_Double() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetDouble(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetDouble(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetDouble(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetDouble(); } + _dataTable = new DataTable(_data1, _data2, new Double[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Arm64.MultiplyExtendedScalar( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Arm64.MultiplyExtendedScalar( + AdvSimd.LoadVector64((Double*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Double*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.MultiplyExtendedScalar), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.MultiplyExtendedScalar), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Double*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Double*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Arm64.MultiplyExtendedScalar( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.Arm64.MultiplyExtendedScalar( + AdvSimd.LoadVector64((Double*)(pClsVar1)), + AdvSimd.LoadVector64((Double*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.Arm64.MultiplyExtendedScalar(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Double*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Double*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.Arm64.MultiplyExtendedScalar(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__MultiplyExtendedScalar_Vector64_Double(); + var result = AdvSimd.Arm64.MultiplyExtendedScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__MultiplyExtendedScalar_Vector64_Double(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.Arm64.MultiplyExtendedScalar( + AdvSimd.LoadVector64((Double*)(pFld1)), + AdvSimd.LoadVector64((Double*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Arm64.MultiplyExtendedScalar(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.Arm64.MultiplyExtendedScalar( + AdvSimd.LoadVector64((Double*)(pFld1)), + AdvSimd.LoadVector64((Double*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.MultiplyExtendedScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.MultiplyExtendedScalar( + AdvSimd.LoadVector64((Double*)(&test._fld1)), + AdvSimd.LoadVector64((Double*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + Double[] inArray1 = new Double[Op1ElementCount]; + Double[] inArray2 = new Double[Op2ElementCount]; + Double[] outArray = new Double[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, 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(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Double[] left, Double[] right, Double[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (BitConverter.DoubleToInt64Bits(Helpers.MultiplyExtended(left[0], right[0])) != BitConverter.DoubleToInt64Bits(result[0])) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (BitConverter.DoubleToInt64Bits(result[i]) != 0) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.MultiplyExtendedScalar)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/MultiplyExtendedScalar.Vector64.Single.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/MultiplyExtendedScalar.Vector64.Single.cs new file mode 100644 index 00000000000000..6826a746d18677 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/MultiplyExtendedScalar.Vector64.Single.cs @@ -0,0 +1,537 @@ +// 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.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void MultiplyExtendedScalar_Vector64_Single() + { + var test = new SimpleBinaryOpTest__MultiplyExtendedScalar_Vector64_Single(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + 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__MultiplyExtendedScalar_Vector64_Single + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Single[] inArray1, Single[] inArray2, Single[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSingle(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSingle(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__MultiplyExtendedScalar_Vector64_Single testClass) + { + var result = AdvSimd.Arm64.MultiplyExtendedScalar(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__MultiplyExtendedScalar_Vector64_Single testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.Arm64.MultiplyExtendedScalar( + AdvSimd.LoadVector64((Single*)(pFld1)), + AdvSimd.LoadVector64((Single*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Single); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Single); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Single); + + private static Single[] _data1 = new Single[Op1ElementCount]; + private static Single[] _data2 = new Single[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__MultiplyExtendedScalar_Vector64_Single() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSingle(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSingle(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__MultiplyExtendedScalar_Vector64_Single() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSingle(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSingle(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSingle(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSingle(); } + _dataTable = new DataTable(_data1, _data2, new Single[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Arm64.MultiplyExtendedScalar( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Arm64.MultiplyExtendedScalar( + AdvSimd.LoadVector64((Single*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Single*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.MultiplyExtendedScalar), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.MultiplyExtendedScalar), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Single*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Single*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Arm64.MultiplyExtendedScalar( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.Arm64.MultiplyExtendedScalar( + AdvSimd.LoadVector64((Single*)(pClsVar1)), + AdvSimd.LoadVector64((Single*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.Arm64.MultiplyExtendedScalar(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Single*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Single*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.Arm64.MultiplyExtendedScalar(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__MultiplyExtendedScalar_Vector64_Single(); + var result = AdvSimd.Arm64.MultiplyExtendedScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__MultiplyExtendedScalar_Vector64_Single(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.Arm64.MultiplyExtendedScalar( + AdvSimd.LoadVector64((Single*)(pFld1)), + AdvSimd.LoadVector64((Single*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Arm64.MultiplyExtendedScalar(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.Arm64.MultiplyExtendedScalar( + AdvSimd.LoadVector64((Single*)(pFld1)), + AdvSimd.LoadVector64((Single*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.MultiplyExtendedScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.MultiplyExtendedScalar( + AdvSimd.LoadVector64((Single*)(&test._fld1)), + AdvSimd.LoadVector64((Single*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + Single[] inArray1 = new Single[Op1ElementCount]; + Single[] inArray2 = new Single[Op2ElementCount]; + Single[] outArray = new Single[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, 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(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Single[] left, Single[] right, Single[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (BitConverter.SingleToInt32Bits(Helpers.MultiplyExtended(left[0], right[0])) != BitConverter.SingleToInt32Bits(result[0])) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (BitConverter.SingleToInt32Bits(result[i]) != 0) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.MultiplyExtendedScalar)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/Program.AdvSimd.Arm64.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/Program.AdvSimd.Arm64.cs index df6f661b6aa4ae..405efb58d4dd95 100644 --- a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/Program.AdvSimd.Arm64.cs +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/Program.AdvSimd.Arm64.cs @@ -164,9 +164,28 @@ static Program() ["MinScalar.Vector64.Double"] = MinScalar_Vector64_Double, ["MinScalar.Vector64.Single"] = MinScalar_Vector64_Single, ["Multiply.Vector128.Double"] = Multiply_Vector128_Double, + ["MultiplyExtended.Vector64.Single"] = MultiplyExtended_Vector64_Single, + ["MultiplyExtended.Vector128.Double"] = MultiplyExtended_Vector128_Double, + ["MultiplyExtended.Vector128.Single"] = MultiplyExtended_Vector128_Single, + ["MultiplyExtendedScalar.Vector64.Double"] = MultiplyExtendedScalar_Vector64_Double, + ["MultiplyExtendedScalar.Vector64.Single"] = MultiplyExtendedScalar_Vector64_Single, ["Negate.Vector128.Double"] = Negate_Vector128_Double, ["Negate.Vector128.Int64"] = Negate_Vector128_Int64, ["NegateScalar.Vector64.Int64"] = NegateScalar_Vector64_Int64, + ["ReciprocalEstimate.Vector128.Double"] = ReciprocalEstimate_Vector128_Double, + ["ReciprocalEstimateScalar.Vector64.Double"] = ReciprocalEstimateScalar_Vector64_Double, + ["ReciprocalEstimateScalar.Vector64.Single"] = ReciprocalEstimateScalar_Vector64_Single, + ["ReciprocalExponentScalar.Vector64.Double"] = ReciprocalExponentScalar_Vector64_Double, + ["ReciprocalExponentScalar.Vector64.Single"] = ReciprocalExponentScalar_Vector64_Single, + ["ReciprocalSquareRootEstimate.Vector128.Double"] = ReciprocalSquareRootEstimate_Vector128_Double, + ["ReciprocalSquareRootEstimateScalar.Vector64.Double"] = ReciprocalSquareRootEstimateScalar_Vector64_Double, + ["ReciprocalSquareRootEstimateScalar.Vector64.Single"] = ReciprocalSquareRootEstimateScalar_Vector64_Single, + ["ReciprocalSquareRootStep.Vector128.Double"] = ReciprocalSquareRootStep_Vector128_Double, + ["ReciprocalSquareRootStepScalar.Vector64.Double"] = ReciprocalSquareRootStepScalar_Vector64_Double, + ["ReciprocalSquareRootStepScalar.Vector64.Single"] = ReciprocalSquareRootStepScalar_Vector64_Single, + ["ReciprocalStep.Vector128.Double"] = ReciprocalStep_Vector128_Double, + ["ReciprocalStepScalar.Vector64.Double"] = ReciprocalStepScalar_Vector64_Double, + ["ReciprocalStepScalar.Vector64.Single"] = ReciprocalStepScalar_Vector64_Single, ["ReverseElementBits.Vector128.Byte"] = ReverseElementBits_Vector128_Byte, ["ReverseElementBits.Vector128.SByte"] = ReverseElementBits_Vector128_SByte, ["ReverseElementBits.Vector64.Byte"] = ReverseElementBits_Vector64_Byte, diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ReciprocalEstimate.Vector128.Double.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ReciprocalEstimate.Vector128.Double.cs new file mode 100644 index 00000000000000..989d73b7b2333c --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ReciprocalEstimate.Vector128.Double.cs @@ -0,0 +1,489 @@ +// 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.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ReciprocalEstimate_Vector128_Double() + { + var test = new SimpleUnaryOpTest__ReciprocalEstimate_Vector128_Double(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + 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__ReciprocalEstimate_Vector128_Double + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Double[] inArray1, Double[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = BitConverter.Int64BitsToDouble(0x3fc9db3dab555868); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleUnaryOpTest__ReciprocalEstimate_Vector128_Double testClass) + { + var result = AdvSimd.Arm64.ReciprocalEstimate(_fld1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleUnaryOpTest__ReciprocalEstimate_Vector128_Double testClass) + { + fixed (Vector128* pFld1 = &_fld1) + { + var result = AdvSimd.Arm64.ReciprocalEstimate( + AdvSimd.LoadVector128((Double*)(pFld1)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Double); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Double); + + private static Double[] _data1 = new Double[Op1ElementCount]; + + private static Vector128 _clsVar1; + + private Vector128 _fld1; + + private DataTable _dataTable; + + static SimpleUnaryOpTest__ReciprocalEstimate_Vector128_Double() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = BitConverter.Int64BitsToDouble(0x3fc9db3dab555868); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleUnaryOpTest__ReciprocalEstimate_Vector128_Double() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = BitConverter.Int64BitsToDouble(0x3fc9db3dab555868); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = BitConverter.Int64BitsToDouble(0x3fc9db3dab555868); } + _dataTable = new DataTable(_data1, new Double[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Arm64.ReciprocalEstimate( + Unsafe.Read>(_dataTable.inArray1Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Arm64.ReciprocalEstimate( + AdvSimd.LoadVector128((Double*)(_dataTable.inArray1Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ReciprocalEstimate), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ReciprocalEstimate), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Double*)(_dataTable.inArray1Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Arm64.ReciprocalEstimate( + _clsVar1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + { + var result = AdvSimd.Arm64.ReciprocalEstimate( + AdvSimd.LoadVector128((Double*)(pClsVar1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var result = AdvSimd.Arm64.ReciprocalEstimate(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Double*)(_dataTable.inArray1Ptr)); + var result = AdvSimd.Arm64.ReciprocalEstimate(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleUnaryOpTest__ReciprocalEstimate_Vector128_Double(); + var result = AdvSimd.Arm64.ReciprocalEstimate(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleUnaryOpTest__ReciprocalEstimate_Vector128_Double(); + + fixed (Vector128* pFld1 = &test._fld1) + { + var result = AdvSimd.Arm64.ReciprocalEstimate( + AdvSimd.LoadVector128((Double*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Arm64.ReciprocalEstimate(_fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + { + var result = AdvSimd.Arm64.ReciprocalEstimate( + AdvSimd.LoadVector128((Double*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ReciprocalEstimate(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ReciprocalEstimate( + AdvSimd.LoadVector128((Double*)(&test._fld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, void* result, [CallerMemberName] string method = "") + { + Double[] inArray1 = new Double[Op1ElementCount]; + Double[] outArray = new Double[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(void* op1, void* result, [CallerMemberName] string method = "") + { + Double[] inArray1 = new Double[Op1ElementCount]; + Double[] outArray = new Double[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(Double[] firstOp, Double[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (BitConverter.DoubleToInt64Bits(result[i]) != 0x4013d00000000000) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.ReciprocalEstimate)}(Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ReciprocalEstimateScalar.Vector64.Double.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ReciprocalEstimateScalar.Vector64.Double.cs new file mode 100644 index 00000000000000..fc5109b3c17adc --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ReciprocalEstimateScalar.Vector64.Double.cs @@ -0,0 +1,496 @@ +// 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.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ReciprocalEstimateScalar_Vector64_Double() + { + var test = new SimpleUnaryOpTest__ReciprocalEstimateScalar_Vector64_Double(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + 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__ReciprocalEstimateScalar_Vector64_Double + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Double[] inArray1, Double[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = BitConverter.Int64BitsToDouble(0x3fc9db3dab555868); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleUnaryOpTest__ReciprocalEstimateScalar_Vector64_Double testClass) + { + var result = AdvSimd.Arm64.ReciprocalEstimateScalar(_fld1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleUnaryOpTest__ReciprocalEstimateScalar_Vector64_Double testClass) + { + fixed (Vector64* pFld1 = &_fld1) + { + var result = AdvSimd.Arm64.ReciprocalEstimateScalar( + AdvSimd.LoadVector64((Double*)(pFld1)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Double); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Double); + + private static Double[] _data1 = new Double[Op1ElementCount]; + + private static Vector64 _clsVar1; + + private Vector64 _fld1; + + private DataTable _dataTable; + + static SimpleUnaryOpTest__ReciprocalEstimateScalar_Vector64_Double() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = BitConverter.Int64BitsToDouble(0x3fc9db3dab555868); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleUnaryOpTest__ReciprocalEstimateScalar_Vector64_Double() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = BitConverter.Int64BitsToDouble(0x3fc9db3dab555868); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = BitConverter.Int64BitsToDouble(0x3fc9db3dab555868); } + _dataTable = new DataTable(_data1, new Double[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Arm64.ReciprocalEstimateScalar( + Unsafe.Read>(_dataTable.inArray1Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Arm64.ReciprocalEstimateScalar( + AdvSimd.LoadVector64((Double*)(_dataTable.inArray1Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ReciprocalEstimateScalar), new Type[] { typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ReciprocalEstimateScalar), new Type[] { typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Double*)(_dataTable.inArray1Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Arm64.ReciprocalEstimateScalar( + _clsVar1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + { + var result = AdvSimd.Arm64.ReciprocalEstimateScalar( + AdvSimd.LoadVector64((Double*)(pClsVar1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var result = AdvSimd.Arm64.ReciprocalEstimateScalar(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Double*)(_dataTable.inArray1Ptr)); + var result = AdvSimd.Arm64.ReciprocalEstimateScalar(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleUnaryOpTest__ReciprocalEstimateScalar_Vector64_Double(); + var result = AdvSimd.Arm64.ReciprocalEstimateScalar(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleUnaryOpTest__ReciprocalEstimateScalar_Vector64_Double(); + + fixed (Vector64* pFld1 = &test._fld1) + { + var result = AdvSimd.Arm64.ReciprocalEstimateScalar( + AdvSimd.LoadVector64((Double*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Arm64.ReciprocalEstimateScalar(_fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + { + var result = AdvSimd.Arm64.ReciprocalEstimateScalar( + AdvSimd.LoadVector64((Double*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ReciprocalEstimateScalar(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ReciprocalEstimateScalar( + AdvSimd.LoadVector64((Double*)(&test._fld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, void* result, [CallerMemberName] string method = "") + { + Double[] inArray1 = new Double[Op1ElementCount]; + Double[] outArray = new Double[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(void* op1, void* result, [CallerMemberName] string method = "") + { + Double[] inArray1 = new Double[Op1ElementCount]; + Double[] outArray = new Double[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(Double[] firstOp, Double[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (BitConverter.DoubleToInt64Bits(result[0]) != 0x4013d00000000000) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (BitConverter.DoubleToInt64Bits(result[i]) != 0) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.ReciprocalEstimateScalar)}(Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ReciprocalEstimateScalar.Vector64.Single.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ReciprocalEstimateScalar.Vector64.Single.cs new file mode 100644 index 00000000000000..d09414dae14bd6 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ReciprocalEstimateScalar.Vector64.Single.cs @@ -0,0 +1,496 @@ +// 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.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ReciprocalEstimateScalar_Vector64_Single() + { + var test = new SimpleUnaryOpTest__ReciprocalEstimateScalar_Vector64_Single(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + 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__ReciprocalEstimateScalar_Vector64_Single + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Single[] inArray1, Single[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = BitConverter.Int32BitsToSingle(0x3e4ed9ed); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleUnaryOpTest__ReciprocalEstimateScalar_Vector64_Single testClass) + { + var result = AdvSimd.Arm64.ReciprocalEstimateScalar(_fld1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleUnaryOpTest__ReciprocalEstimateScalar_Vector64_Single testClass) + { + fixed (Vector64* pFld1 = &_fld1) + { + var result = AdvSimd.Arm64.ReciprocalEstimateScalar( + AdvSimd.LoadVector64((Single*)(pFld1)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Single); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Single); + + private static Single[] _data1 = new Single[Op1ElementCount]; + + private static Vector64 _clsVar1; + + private Vector64 _fld1; + + private DataTable _dataTable; + + static SimpleUnaryOpTest__ReciprocalEstimateScalar_Vector64_Single() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = BitConverter.Int32BitsToSingle(0x3e4ed9ed); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleUnaryOpTest__ReciprocalEstimateScalar_Vector64_Single() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = BitConverter.Int32BitsToSingle(0x3e4ed9ed); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = BitConverter.Int32BitsToSingle(0x3e4ed9ed); } + _dataTable = new DataTable(_data1, new Single[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Arm64.ReciprocalEstimateScalar( + Unsafe.Read>(_dataTable.inArray1Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Arm64.ReciprocalEstimateScalar( + AdvSimd.LoadVector64((Single*)(_dataTable.inArray1Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ReciprocalEstimateScalar), new Type[] { typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ReciprocalEstimateScalar), new Type[] { typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Single*)(_dataTable.inArray1Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Arm64.ReciprocalEstimateScalar( + _clsVar1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + { + var result = AdvSimd.Arm64.ReciprocalEstimateScalar( + AdvSimd.LoadVector64((Single*)(pClsVar1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var result = AdvSimd.Arm64.ReciprocalEstimateScalar(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Single*)(_dataTable.inArray1Ptr)); + var result = AdvSimd.Arm64.ReciprocalEstimateScalar(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleUnaryOpTest__ReciprocalEstimateScalar_Vector64_Single(); + var result = AdvSimd.Arm64.ReciprocalEstimateScalar(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleUnaryOpTest__ReciprocalEstimateScalar_Vector64_Single(); + + fixed (Vector64* pFld1 = &test._fld1) + { + var result = AdvSimd.Arm64.ReciprocalEstimateScalar( + AdvSimd.LoadVector64((Single*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Arm64.ReciprocalEstimateScalar(_fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + { + var result = AdvSimd.Arm64.ReciprocalEstimateScalar( + AdvSimd.LoadVector64((Single*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ReciprocalEstimateScalar(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ReciprocalEstimateScalar( + AdvSimd.LoadVector64((Single*)(&test._fld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, void* result, [CallerMemberName] string method = "") + { + Single[] inArray1 = new Single[Op1ElementCount]; + Single[] outArray = new Single[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(void* op1, void* result, [CallerMemberName] string method = "") + { + Single[] inArray1 = new Single[Op1ElementCount]; + Single[] outArray = new Single[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(Single[] firstOp, Single[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (BitConverter.SingleToInt32Bits(result[0]) != 0x409e8000) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (BitConverter.SingleToInt32Bits(result[i]) != 0) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.ReciprocalEstimateScalar)}(Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ReciprocalExponentScalar.Vector64.Double.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ReciprocalExponentScalar.Vector64.Double.cs new file mode 100644 index 00000000000000..6d2dc1c8a00e95 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ReciprocalExponentScalar.Vector64.Double.cs @@ -0,0 +1,496 @@ +// 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.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ReciprocalExponentScalar_Vector64_Double() + { + var test = new SimpleUnaryOpTest__ReciprocalExponentScalar_Vector64_Double(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + 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__ReciprocalExponentScalar_Vector64_Double + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Double[] inArray1, Double[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = BitConverter.Int64BitsToDouble(0x3fc9db3dab555868); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleUnaryOpTest__ReciprocalExponentScalar_Vector64_Double testClass) + { + var result = AdvSimd.Arm64.ReciprocalExponentScalar(_fld1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleUnaryOpTest__ReciprocalExponentScalar_Vector64_Double testClass) + { + fixed (Vector64* pFld1 = &_fld1) + { + var result = AdvSimd.Arm64.ReciprocalExponentScalar( + AdvSimd.LoadVector64((Double*)(pFld1)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Double); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Double); + + private static Double[] _data1 = new Double[Op1ElementCount]; + + private static Vector64 _clsVar1; + + private Vector64 _fld1; + + private DataTable _dataTable; + + static SimpleUnaryOpTest__ReciprocalExponentScalar_Vector64_Double() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = BitConverter.Int64BitsToDouble(0x3fc9db3dab555868); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleUnaryOpTest__ReciprocalExponentScalar_Vector64_Double() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = BitConverter.Int64BitsToDouble(0x3fc9db3dab555868); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = BitConverter.Int64BitsToDouble(0x3fc9db3dab555868); } + _dataTable = new DataTable(_data1, new Double[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Arm64.ReciprocalExponentScalar( + Unsafe.Read>(_dataTable.inArray1Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Arm64.ReciprocalExponentScalar( + AdvSimd.LoadVector64((Double*)(_dataTable.inArray1Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ReciprocalExponentScalar), new Type[] { typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ReciprocalExponentScalar), new Type[] { typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Double*)(_dataTable.inArray1Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Arm64.ReciprocalExponentScalar( + _clsVar1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + { + var result = AdvSimd.Arm64.ReciprocalExponentScalar( + AdvSimd.LoadVector64((Double*)(pClsVar1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var result = AdvSimd.Arm64.ReciprocalExponentScalar(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Double*)(_dataTable.inArray1Ptr)); + var result = AdvSimd.Arm64.ReciprocalExponentScalar(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleUnaryOpTest__ReciprocalExponentScalar_Vector64_Double(); + var result = AdvSimd.Arm64.ReciprocalExponentScalar(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleUnaryOpTest__ReciprocalExponentScalar_Vector64_Double(); + + fixed (Vector64* pFld1 = &test._fld1) + { + var result = AdvSimd.Arm64.ReciprocalExponentScalar( + AdvSimd.LoadVector64((Double*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Arm64.ReciprocalExponentScalar(_fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + { + var result = AdvSimd.Arm64.ReciprocalExponentScalar( + AdvSimd.LoadVector64((Double*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ReciprocalExponentScalar(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ReciprocalExponentScalar( + AdvSimd.LoadVector64((Double*)(&test._fld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, void* result, [CallerMemberName] string method = "") + { + Double[] inArray1 = new Double[Op1ElementCount]; + Double[] outArray = new Double[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(void* op1, void* result, [CallerMemberName] string method = "") + { + Double[] inArray1 = new Double[Op1ElementCount]; + Double[] outArray = new Double[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(Double[] firstOp, Double[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (BitConverter.DoubleToInt64Bits(result[0]) != 0x4030000000000000) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (BitConverter.DoubleToInt64Bits(result[i]) != 0) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.ReciprocalExponentScalar)}(Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ReciprocalExponentScalar.Vector64.Single.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ReciprocalExponentScalar.Vector64.Single.cs new file mode 100644 index 00000000000000..6118ed7c9237a7 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ReciprocalExponentScalar.Vector64.Single.cs @@ -0,0 +1,496 @@ +// 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.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ReciprocalExponentScalar_Vector64_Single() + { + var test = new SimpleUnaryOpTest__ReciprocalExponentScalar_Vector64_Single(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + 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__ReciprocalExponentScalar_Vector64_Single + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Single[] inArray1, Single[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = BitConverter.Int32BitsToSingle(0x3e4ed9ed); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleUnaryOpTest__ReciprocalExponentScalar_Vector64_Single testClass) + { + var result = AdvSimd.Arm64.ReciprocalExponentScalar(_fld1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleUnaryOpTest__ReciprocalExponentScalar_Vector64_Single testClass) + { + fixed (Vector64* pFld1 = &_fld1) + { + var result = AdvSimd.Arm64.ReciprocalExponentScalar( + AdvSimd.LoadVector64((Single*)(pFld1)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Single); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Single); + + private static Single[] _data1 = new Single[Op1ElementCount]; + + private static Vector64 _clsVar1; + + private Vector64 _fld1; + + private DataTable _dataTable; + + static SimpleUnaryOpTest__ReciprocalExponentScalar_Vector64_Single() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = BitConverter.Int32BitsToSingle(0x3e4ed9ed); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleUnaryOpTest__ReciprocalExponentScalar_Vector64_Single() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = BitConverter.Int32BitsToSingle(0x3e4ed9ed); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = BitConverter.Int32BitsToSingle(0x3e4ed9ed); } + _dataTable = new DataTable(_data1, new Single[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Arm64.ReciprocalExponentScalar( + Unsafe.Read>(_dataTable.inArray1Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Arm64.ReciprocalExponentScalar( + AdvSimd.LoadVector64((Single*)(_dataTable.inArray1Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ReciprocalExponentScalar), new Type[] { typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ReciprocalExponentScalar), new Type[] { typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Single*)(_dataTable.inArray1Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Arm64.ReciprocalExponentScalar( + _clsVar1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + { + var result = AdvSimd.Arm64.ReciprocalExponentScalar( + AdvSimd.LoadVector64((Single*)(pClsVar1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var result = AdvSimd.Arm64.ReciprocalExponentScalar(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Single*)(_dataTable.inArray1Ptr)); + var result = AdvSimd.Arm64.ReciprocalExponentScalar(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleUnaryOpTest__ReciprocalExponentScalar_Vector64_Single(); + var result = AdvSimd.Arm64.ReciprocalExponentScalar(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleUnaryOpTest__ReciprocalExponentScalar_Vector64_Single(); + + fixed (Vector64* pFld1 = &test._fld1) + { + var result = AdvSimd.Arm64.ReciprocalExponentScalar( + AdvSimd.LoadVector64((Single*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Arm64.ReciprocalExponentScalar(_fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + { + var result = AdvSimd.Arm64.ReciprocalExponentScalar( + AdvSimd.LoadVector64((Single*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ReciprocalExponentScalar(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ReciprocalExponentScalar( + AdvSimd.LoadVector64((Single*)(&test._fld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, void* result, [CallerMemberName] string method = "") + { + Single[] inArray1 = new Single[Op1ElementCount]; + Single[] outArray = new Single[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(void* op1, void* result, [CallerMemberName] string method = "") + { + Single[] inArray1 = new Single[Op1ElementCount]; + Single[] outArray = new Single[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(Single[] firstOp, Single[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (BitConverter.SingleToInt32Bits(result[0]) != 0x41800000) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (BitConverter.SingleToInt32Bits(result[i]) != 0) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.ReciprocalExponentScalar)}(Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ReciprocalSquareRootEstimate.Vector128.Double.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ReciprocalSquareRootEstimate.Vector128.Double.cs new file mode 100644 index 00000000000000..73b038c5b5c0ff --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ReciprocalSquareRootEstimate.Vector128.Double.cs @@ -0,0 +1,489 @@ +// 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.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ReciprocalSquareRootEstimate_Vector128_Double() + { + var test = new SimpleUnaryOpTest__ReciprocalSquareRootEstimate_Vector128_Double(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + 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__ReciprocalSquareRootEstimate_Vector128_Double + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Double[] inArray1, Double[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = BitConverter.Int64BitsToDouble(0x3fc9db3dab555868); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleUnaryOpTest__ReciprocalSquareRootEstimate_Vector128_Double testClass) + { + var result = AdvSimd.Arm64.ReciprocalSquareRootEstimate(_fld1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleUnaryOpTest__ReciprocalSquareRootEstimate_Vector128_Double testClass) + { + fixed (Vector128* pFld1 = &_fld1) + { + var result = AdvSimd.Arm64.ReciprocalSquareRootEstimate( + AdvSimd.LoadVector128((Double*)(pFld1)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Double); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Double); + + private static Double[] _data1 = new Double[Op1ElementCount]; + + private static Vector128 _clsVar1; + + private Vector128 _fld1; + + private DataTable _dataTable; + + static SimpleUnaryOpTest__ReciprocalSquareRootEstimate_Vector128_Double() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = BitConverter.Int64BitsToDouble(0x3fc9db3dab555868); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleUnaryOpTest__ReciprocalSquareRootEstimate_Vector128_Double() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = BitConverter.Int64BitsToDouble(0x3fc9db3dab555868); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = BitConverter.Int64BitsToDouble(0x3fc9db3dab555868); } + _dataTable = new DataTable(_data1, new Double[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Arm64.ReciprocalSquareRootEstimate( + Unsafe.Read>(_dataTable.inArray1Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Arm64.ReciprocalSquareRootEstimate( + AdvSimd.LoadVector128((Double*)(_dataTable.inArray1Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ReciprocalSquareRootEstimate), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ReciprocalSquareRootEstimate), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Double*)(_dataTable.inArray1Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Arm64.ReciprocalSquareRootEstimate( + _clsVar1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + { + var result = AdvSimd.Arm64.ReciprocalSquareRootEstimate( + AdvSimd.LoadVector128((Double*)(pClsVar1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var result = AdvSimd.Arm64.ReciprocalSquareRootEstimate(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Double*)(_dataTable.inArray1Ptr)); + var result = AdvSimd.Arm64.ReciprocalSquareRootEstimate(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleUnaryOpTest__ReciprocalSquareRootEstimate_Vector128_Double(); + var result = AdvSimd.Arm64.ReciprocalSquareRootEstimate(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleUnaryOpTest__ReciprocalSquareRootEstimate_Vector128_Double(); + + fixed (Vector128* pFld1 = &test._fld1) + { + var result = AdvSimd.Arm64.ReciprocalSquareRootEstimate( + AdvSimd.LoadVector128((Double*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Arm64.ReciprocalSquareRootEstimate(_fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + { + var result = AdvSimd.Arm64.ReciprocalSquareRootEstimate( + AdvSimd.LoadVector128((Double*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ReciprocalSquareRootEstimate(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ReciprocalSquareRootEstimate( + AdvSimd.LoadVector128((Double*)(&test._fld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, void* result, [CallerMemberName] string method = "") + { + Double[] inArray1 = new Double[Op1ElementCount]; + Double[] outArray = new Double[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(void* op1, void* result, [CallerMemberName] string method = "") + { + Double[] inArray1 = new Double[Op1ElementCount]; + Double[] outArray = new Double[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(Double[] firstOp, Double[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if ( BitConverter.DoubleToInt64Bits(result[i]) != 0x4001d00000000000) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.ReciprocalSquareRootEstimate)}(Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ReciprocalSquareRootEstimateScalar.Vector64.Double.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ReciprocalSquareRootEstimateScalar.Vector64.Double.cs new file mode 100644 index 00000000000000..a240de078ff6e4 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ReciprocalSquareRootEstimateScalar.Vector64.Double.cs @@ -0,0 +1,496 @@ +// 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.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ReciprocalSquareRootEstimateScalar_Vector64_Double() + { + var test = new SimpleUnaryOpTest__ReciprocalSquareRootEstimateScalar_Vector64_Double(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + 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__ReciprocalSquareRootEstimateScalar_Vector64_Double + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Double[] inArray1, Double[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = BitConverter.Int64BitsToDouble(0x3fc9db3dab555868); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleUnaryOpTest__ReciprocalSquareRootEstimateScalar_Vector64_Double testClass) + { + var result = AdvSimd.Arm64.ReciprocalSquareRootEstimateScalar(_fld1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleUnaryOpTest__ReciprocalSquareRootEstimateScalar_Vector64_Double testClass) + { + fixed (Vector64* pFld1 = &_fld1) + { + var result = AdvSimd.Arm64.ReciprocalSquareRootEstimateScalar( + AdvSimd.LoadVector64((Double*)(pFld1)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Double); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Double); + + private static Double[] _data1 = new Double[Op1ElementCount]; + + private static Vector64 _clsVar1; + + private Vector64 _fld1; + + private DataTable _dataTable; + + static SimpleUnaryOpTest__ReciprocalSquareRootEstimateScalar_Vector64_Double() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = BitConverter.Int64BitsToDouble(0x3fc9db3dab555868); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleUnaryOpTest__ReciprocalSquareRootEstimateScalar_Vector64_Double() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = BitConverter.Int64BitsToDouble(0x3fc9db3dab555868); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = BitConverter.Int64BitsToDouble(0x3fc9db3dab555868); } + _dataTable = new DataTable(_data1, new Double[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Arm64.ReciprocalSquareRootEstimateScalar( + Unsafe.Read>(_dataTable.inArray1Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Arm64.ReciprocalSquareRootEstimateScalar( + AdvSimd.LoadVector64((Double*)(_dataTable.inArray1Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ReciprocalSquareRootEstimateScalar), new Type[] { typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ReciprocalSquareRootEstimateScalar), new Type[] { typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Double*)(_dataTable.inArray1Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Arm64.ReciprocalSquareRootEstimateScalar( + _clsVar1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + { + var result = AdvSimd.Arm64.ReciprocalSquareRootEstimateScalar( + AdvSimd.LoadVector64((Double*)(pClsVar1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var result = AdvSimd.Arm64.ReciprocalSquareRootEstimateScalar(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Double*)(_dataTable.inArray1Ptr)); + var result = AdvSimd.Arm64.ReciprocalSquareRootEstimateScalar(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleUnaryOpTest__ReciprocalSquareRootEstimateScalar_Vector64_Double(); + var result = AdvSimd.Arm64.ReciprocalSquareRootEstimateScalar(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleUnaryOpTest__ReciprocalSquareRootEstimateScalar_Vector64_Double(); + + fixed (Vector64* pFld1 = &test._fld1) + { + var result = AdvSimd.Arm64.ReciprocalSquareRootEstimateScalar( + AdvSimd.LoadVector64((Double*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Arm64.ReciprocalSquareRootEstimateScalar(_fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + { + var result = AdvSimd.Arm64.ReciprocalSquareRootEstimateScalar( + AdvSimd.LoadVector64((Double*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ReciprocalSquareRootEstimateScalar(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ReciprocalSquareRootEstimateScalar( + AdvSimd.LoadVector64((Double*)(&test._fld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, void* result, [CallerMemberName] string method = "") + { + Double[] inArray1 = new Double[Op1ElementCount]; + Double[] outArray = new Double[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(void* op1, void* result, [CallerMemberName] string method = "") + { + Double[] inArray1 = new Double[Op1ElementCount]; + Double[] outArray = new Double[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(Double[] firstOp, Double[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (BitConverter.DoubleToInt64Bits(result[0]) != 0x4001d00000000000) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (BitConverter.DoubleToInt64Bits(result[i]) != 0) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.ReciprocalSquareRootEstimateScalar)}(Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ReciprocalSquareRootEstimateScalar.Vector64.Single.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ReciprocalSquareRootEstimateScalar.Vector64.Single.cs new file mode 100644 index 00000000000000..090a51cae4e4c2 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ReciprocalSquareRootEstimateScalar.Vector64.Single.cs @@ -0,0 +1,496 @@ +// 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.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ReciprocalSquareRootEstimateScalar_Vector64_Single() + { + var test = new SimpleUnaryOpTest__ReciprocalSquareRootEstimateScalar_Vector64_Single(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + 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__ReciprocalSquareRootEstimateScalar_Vector64_Single + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Single[] inArray1, Single[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = BitConverter.Int32BitsToSingle(0x3e4ed9ed); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleUnaryOpTest__ReciprocalSquareRootEstimateScalar_Vector64_Single testClass) + { + var result = AdvSimd.Arm64.ReciprocalSquareRootEstimateScalar(_fld1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleUnaryOpTest__ReciprocalSquareRootEstimateScalar_Vector64_Single testClass) + { + fixed (Vector64* pFld1 = &_fld1) + { + var result = AdvSimd.Arm64.ReciprocalSquareRootEstimateScalar( + AdvSimd.LoadVector64((Single*)(pFld1)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Single); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Single); + + private static Single[] _data1 = new Single[Op1ElementCount]; + + private static Vector64 _clsVar1; + + private Vector64 _fld1; + + private DataTable _dataTable; + + static SimpleUnaryOpTest__ReciprocalSquareRootEstimateScalar_Vector64_Single() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = BitConverter.Int32BitsToSingle(0x3e4ed9ed); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleUnaryOpTest__ReciprocalSquareRootEstimateScalar_Vector64_Single() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = BitConverter.Int32BitsToSingle(0x3e4ed9ed); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = BitConverter.Int32BitsToSingle(0x3e4ed9ed); } + _dataTable = new DataTable(_data1, new Single[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Arm64.ReciprocalSquareRootEstimateScalar( + Unsafe.Read>(_dataTable.inArray1Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Arm64.ReciprocalSquareRootEstimateScalar( + AdvSimd.LoadVector64((Single*)(_dataTable.inArray1Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ReciprocalSquareRootEstimateScalar), new Type[] { typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ReciprocalSquareRootEstimateScalar), new Type[] { typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Single*)(_dataTable.inArray1Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Arm64.ReciprocalSquareRootEstimateScalar( + _clsVar1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + { + var result = AdvSimd.Arm64.ReciprocalSquareRootEstimateScalar( + AdvSimd.LoadVector64((Single*)(pClsVar1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var result = AdvSimd.Arm64.ReciprocalSquareRootEstimateScalar(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Single*)(_dataTable.inArray1Ptr)); + var result = AdvSimd.Arm64.ReciprocalSquareRootEstimateScalar(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleUnaryOpTest__ReciprocalSquareRootEstimateScalar_Vector64_Single(); + var result = AdvSimd.Arm64.ReciprocalSquareRootEstimateScalar(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleUnaryOpTest__ReciprocalSquareRootEstimateScalar_Vector64_Single(); + + fixed (Vector64* pFld1 = &test._fld1) + { + var result = AdvSimd.Arm64.ReciprocalSquareRootEstimateScalar( + AdvSimd.LoadVector64((Single*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Arm64.ReciprocalSquareRootEstimateScalar(_fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + { + var result = AdvSimd.Arm64.ReciprocalSquareRootEstimateScalar( + AdvSimd.LoadVector64((Single*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ReciprocalSquareRootEstimateScalar(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ReciprocalSquareRootEstimateScalar( + AdvSimd.LoadVector64((Single*)(&test._fld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, void* result, [CallerMemberName] string method = "") + { + Single[] inArray1 = new Single[Op1ElementCount]; + Single[] outArray = new Single[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(void* op1, void* result, [CallerMemberName] string method = "") + { + Single[] inArray1 = new Single[Op1ElementCount]; + Single[] outArray = new Single[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(Single[] firstOp, Single[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (BitConverter.SingleToInt32Bits(result[0]) != 0x400e8000) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (BitConverter.SingleToInt32Bits(result[i]) != 0) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.ReciprocalSquareRootEstimateScalar)}(Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ReciprocalSquareRootStep.Vector128.Double.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ReciprocalSquareRootStep.Vector128.Double.cs new file mode 100644 index 00000000000000..273a245e2e8563 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ReciprocalSquareRootStep.Vector128.Double.cs @@ -0,0 +1,530 @@ +// 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.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ReciprocalSquareRootStep_Vector128_Double() + { + var test = new SimpleBinaryOpTest__ReciprocalSquareRootStep_Vector128_Double(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + 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__ReciprocalSquareRootStep_Vector128_Double + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Double[] inArray1, Double[] inArray2, Double[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetDouble(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetDouble(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ReciprocalSquareRootStep_Vector128_Double testClass) + { + var result = AdvSimd.Arm64.ReciprocalSquareRootStep(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ReciprocalSquareRootStep_Vector128_Double testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.Arm64.ReciprocalSquareRootStep( + AdvSimd.LoadVector128((Double*)(pFld1)), + AdvSimd.LoadVector128((Double*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Double); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Double); + private static readonly int RetElementCount = Unsafe.SizeOf>() / 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 DataTable _dataTable; + + static SimpleBinaryOpTest__ReciprocalSquareRootStep_Vector128_Double() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetDouble(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetDouble(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ReciprocalSquareRootStep_Vector128_Double() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetDouble(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetDouble(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetDouble(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetDouble(); } + _dataTable = new DataTable(_data1, _data2, new Double[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Arm64.ReciprocalSquareRootStep( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Arm64.ReciprocalSquareRootStep( + AdvSimd.LoadVector128((Double*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Double*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ReciprocalSquareRootStep), 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() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ReciprocalSquareRootStep), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Double*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Double*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Arm64.ReciprocalSquareRootStep( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.Arm64.ReciprocalSquareRootStep( + AdvSimd.LoadVector128((Double*)(pClsVar1)), + AdvSimd.LoadVector128((Double*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.Arm64.ReciprocalSquareRootStep(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Double*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Double*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.Arm64.ReciprocalSquareRootStep(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ReciprocalSquareRootStep_Vector128_Double(); + var result = AdvSimd.Arm64.ReciprocalSquareRootStep(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ReciprocalSquareRootStep_Vector128_Double(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.Arm64.ReciprocalSquareRootStep( + AdvSimd.LoadVector128((Double*)(pFld1)), + AdvSimd.LoadVector128((Double*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Arm64.ReciprocalSquareRootStep(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.Arm64.ReciprocalSquareRootStep( + AdvSimd.LoadVector128((Double*)(pFld1)), + AdvSimd.LoadVector128((Double*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ReciprocalSquareRootStep(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ReciprocalSquareRootStep( + AdvSimd.LoadVector128((Double*)(&test._fld1)), + AdvSimd.LoadVector128((Double*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + Double[] inArray1 = new Double[Op1ElementCount]; + Double[] inArray2 = new Double[Op2ElementCount]; + Double[] outArray = new Double[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, 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(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Double[] left, Double[] right, Double[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (BitConverter.DoubleToInt64Bits(Helpers.FPRSqrtStepFused(left[i], right[i])) != BitConverter.DoubleToInt64Bits(result[i])) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.ReciprocalSquareRootStep)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ReciprocalSquareRootStepScalar.Vector64.Double.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ReciprocalSquareRootStepScalar.Vector64.Double.cs new file mode 100644 index 00000000000000..a7660fb6b81a0c --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ReciprocalSquareRootStepScalar.Vector64.Double.cs @@ -0,0 +1,537 @@ +// 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.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ReciprocalSquareRootStepScalar_Vector64_Double() + { + var test = new SimpleBinaryOpTest__ReciprocalSquareRootStepScalar_Vector64_Double(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + 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__ReciprocalSquareRootStepScalar_Vector64_Double + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Double[] inArray1, Double[] inArray2, Double[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetDouble(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetDouble(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ReciprocalSquareRootStepScalar_Vector64_Double testClass) + { + var result = AdvSimd.Arm64.ReciprocalSquareRootStepScalar(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ReciprocalSquareRootStepScalar_Vector64_Double testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.Arm64.ReciprocalSquareRootStepScalar( + AdvSimd.LoadVector64((Double*)(pFld1)), + AdvSimd.LoadVector64((Double*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Double); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Double); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Double); + + private static Double[] _data1 = new Double[Op1ElementCount]; + private static Double[] _data2 = new Double[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ReciprocalSquareRootStepScalar_Vector64_Double() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetDouble(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetDouble(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ReciprocalSquareRootStepScalar_Vector64_Double() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetDouble(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetDouble(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetDouble(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetDouble(); } + _dataTable = new DataTable(_data1, _data2, new Double[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Arm64.ReciprocalSquareRootStepScalar( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Arm64.ReciprocalSquareRootStepScalar( + AdvSimd.LoadVector64((Double*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Double*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ReciprocalSquareRootStepScalar), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ReciprocalSquareRootStepScalar), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Double*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Double*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Arm64.ReciprocalSquareRootStepScalar( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.Arm64.ReciprocalSquareRootStepScalar( + AdvSimd.LoadVector64((Double*)(pClsVar1)), + AdvSimd.LoadVector64((Double*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.Arm64.ReciprocalSquareRootStepScalar(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Double*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Double*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.Arm64.ReciprocalSquareRootStepScalar(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ReciprocalSquareRootStepScalar_Vector64_Double(); + var result = AdvSimd.Arm64.ReciprocalSquareRootStepScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ReciprocalSquareRootStepScalar_Vector64_Double(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.Arm64.ReciprocalSquareRootStepScalar( + AdvSimd.LoadVector64((Double*)(pFld1)), + AdvSimd.LoadVector64((Double*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Arm64.ReciprocalSquareRootStepScalar(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.Arm64.ReciprocalSquareRootStepScalar( + AdvSimd.LoadVector64((Double*)(pFld1)), + AdvSimd.LoadVector64((Double*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ReciprocalSquareRootStepScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ReciprocalSquareRootStepScalar( + AdvSimd.LoadVector64((Double*)(&test._fld1)), + AdvSimd.LoadVector64((Double*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + Double[] inArray1 = new Double[Op1ElementCount]; + Double[] inArray2 = new Double[Op2ElementCount]; + Double[] outArray = new Double[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, 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(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Double[] left, Double[] right, Double[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (BitConverter.DoubleToInt64Bits(Helpers.FPRSqrtStepFused(left[0], right[0])) != BitConverter.DoubleToInt64Bits(result[0])) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (BitConverter.DoubleToInt64Bits(result[i]) != 0) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.ReciprocalSquareRootStepScalar)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ReciprocalSquareRootStepScalar.Vector64.Single.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ReciprocalSquareRootStepScalar.Vector64.Single.cs new file mode 100644 index 00000000000000..544994e97c2425 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ReciprocalSquareRootStepScalar.Vector64.Single.cs @@ -0,0 +1,537 @@ +// 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.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ReciprocalSquareRootStepScalar_Vector64_Single() + { + var test = new SimpleBinaryOpTest__ReciprocalSquareRootStepScalar_Vector64_Single(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + 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__ReciprocalSquareRootStepScalar_Vector64_Single + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Single[] inArray1, Single[] inArray2, Single[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSingle(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSingle(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ReciprocalSquareRootStepScalar_Vector64_Single testClass) + { + var result = AdvSimd.Arm64.ReciprocalSquareRootStepScalar(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ReciprocalSquareRootStepScalar_Vector64_Single testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.Arm64.ReciprocalSquareRootStepScalar( + AdvSimd.LoadVector64((Single*)(pFld1)), + AdvSimd.LoadVector64((Single*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Single); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Single); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Single); + + private static Single[] _data1 = new Single[Op1ElementCount]; + private static Single[] _data2 = new Single[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ReciprocalSquareRootStepScalar_Vector64_Single() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSingle(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSingle(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ReciprocalSquareRootStepScalar_Vector64_Single() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSingle(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSingle(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSingle(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSingle(); } + _dataTable = new DataTable(_data1, _data2, new Single[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Arm64.ReciprocalSquareRootStepScalar( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Arm64.ReciprocalSquareRootStepScalar( + AdvSimd.LoadVector64((Single*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Single*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ReciprocalSquareRootStepScalar), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ReciprocalSquareRootStepScalar), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Single*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Single*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Arm64.ReciprocalSquareRootStepScalar( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.Arm64.ReciprocalSquareRootStepScalar( + AdvSimd.LoadVector64((Single*)(pClsVar1)), + AdvSimd.LoadVector64((Single*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.Arm64.ReciprocalSquareRootStepScalar(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Single*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Single*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.Arm64.ReciprocalSquareRootStepScalar(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ReciprocalSquareRootStepScalar_Vector64_Single(); + var result = AdvSimd.Arm64.ReciprocalSquareRootStepScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ReciprocalSquareRootStepScalar_Vector64_Single(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.Arm64.ReciprocalSquareRootStepScalar( + AdvSimd.LoadVector64((Single*)(pFld1)), + AdvSimd.LoadVector64((Single*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Arm64.ReciprocalSquareRootStepScalar(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.Arm64.ReciprocalSquareRootStepScalar( + AdvSimd.LoadVector64((Single*)(pFld1)), + AdvSimd.LoadVector64((Single*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ReciprocalSquareRootStepScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ReciprocalSquareRootStepScalar( + AdvSimd.LoadVector64((Single*)(&test._fld1)), + AdvSimd.LoadVector64((Single*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + Single[] inArray1 = new Single[Op1ElementCount]; + Single[] inArray2 = new Single[Op2ElementCount]; + Single[] outArray = new Single[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, 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(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Single[] left, Single[] right, Single[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (BitConverter.SingleToInt32Bits(Helpers.FPRSqrtStepFused(left[0], right[0])) != BitConverter.SingleToInt32Bits(result[0])) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (BitConverter.SingleToInt32Bits(result[i]) != 0) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.ReciprocalSquareRootStepScalar)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ReciprocalStep.Vector128.Double.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ReciprocalStep.Vector128.Double.cs new file mode 100644 index 00000000000000..410c945a6d03b9 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ReciprocalStep.Vector128.Double.cs @@ -0,0 +1,530 @@ +// 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.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ReciprocalStep_Vector128_Double() + { + var test = new SimpleBinaryOpTest__ReciprocalStep_Vector128_Double(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + 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__ReciprocalStep_Vector128_Double + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Double[] inArray1, Double[] inArray2, Double[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetDouble(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetDouble(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ReciprocalStep_Vector128_Double testClass) + { + var result = AdvSimd.Arm64.ReciprocalStep(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ReciprocalStep_Vector128_Double testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.Arm64.ReciprocalStep( + AdvSimd.LoadVector128((Double*)(pFld1)), + AdvSimd.LoadVector128((Double*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Double); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Double); + private static readonly int RetElementCount = Unsafe.SizeOf>() / 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 DataTable _dataTable; + + static SimpleBinaryOpTest__ReciprocalStep_Vector128_Double() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetDouble(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetDouble(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ReciprocalStep_Vector128_Double() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetDouble(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetDouble(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetDouble(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetDouble(); } + _dataTable = new DataTable(_data1, _data2, new Double[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Arm64.ReciprocalStep( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Arm64.ReciprocalStep( + AdvSimd.LoadVector128((Double*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Double*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ReciprocalStep), 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() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ReciprocalStep), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Double*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Double*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Arm64.ReciprocalStep( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.Arm64.ReciprocalStep( + AdvSimd.LoadVector128((Double*)(pClsVar1)), + AdvSimd.LoadVector128((Double*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.Arm64.ReciprocalStep(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Double*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Double*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.Arm64.ReciprocalStep(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ReciprocalStep_Vector128_Double(); + var result = AdvSimd.Arm64.ReciprocalStep(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ReciprocalStep_Vector128_Double(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.Arm64.ReciprocalStep( + AdvSimd.LoadVector128((Double*)(pFld1)), + AdvSimd.LoadVector128((Double*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Arm64.ReciprocalStep(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.Arm64.ReciprocalStep( + AdvSimd.LoadVector128((Double*)(pFld1)), + AdvSimd.LoadVector128((Double*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ReciprocalStep(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ReciprocalStep( + AdvSimd.LoadVector128((Double*)(&test._fld1)), + AdvSimd.LoadVector128((Double*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + Double[] inArray1 = new Double[Op1ElementCount]; + Double[] inArray2 = new Double[Op2ElementCount]; + Double[] outArray = new Double[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, 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(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Double[] left, Double[] right, Double[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (BitConverter.DoubleToInt64Bits(Helpers.FPRecipStepFused(left[i], right[i])) != BitConverter.DoubleToInt64Bits(result[i])) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.ReciprocalStep)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ReciprocalStepScalar.Vector64.Double.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ReciprocalStepScalar.Vector64.Double.cs new file mode 100644 index 00000000000000..48a6cc397ec4bf --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ReciprocalStepScalar.Vector64.Double.cs @@ -0,0 +1,537 @@ +// 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.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ReciprocalStepScalar_Vector64_Double() + { + var test = new SimpleBinaryOpTest__ReciprocalStepScalar_Vector64_Double(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + 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__ReciprocalStepScalar_Vector64_Double + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Double[] inArray1, Double[] inArray2, Double[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetDouble(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetDouble(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ReciprocalStepScalar_Vector64_Double testClass) + { + var result = AdvSimd.Arm64.ReciprocalStepScalar(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ReciprocalStepScalar_Vector64_Double testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.Arm64.ReciprocalStepScalar( + AdvSimd.LoadVector64((Double*)(pFld1)), + AdvSimd.LoadVector64((Double*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Double); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Double); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Double); + + private static Double[] _data1 = new Double[Op1ElementCount]; + private static Double[] _data2 = new Double[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ReciprocalStepScalar_Vector64_Double() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetDouble(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetDouble(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ReciprocalStepScalar_Vector64_Double() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetDouble(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetDouble(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetDouble(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetDouble(); } + _dataTable = new DataTable(_data1, _data2, new Double[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Arm64.ReciprocalStepScalar( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Arm64.ReciprocalStepScalar( + AdvSimd.LoadVector64((Double*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Double*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ReciprocalStepScalar), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ReciprocalStepScalar), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Double*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Double*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Arm64.ReciprocalStepScalar( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.Arm64.ReciprocalStepScalar( + AdvSimd.LoadVector64((Double*)(pClsVar1)), + AdvSimd.LoadVector64((Double*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.Arm64.ReciprocalStepScalar(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Double*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Double*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.Arm64.ReciprocalStepScalar(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ReciprocalStepScalar_Vector64_Double(); + var result = AdvSimd.Arm64.ReciprocalStepScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ReciprocalStepScalar_Vector64_Double(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.Arm64.ReciprocalStepScalar( + AdvSimd.LoadVector64((Double*)(pFld1)), + AdvSimd.LoadVector64((Double*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Arm64.ReciprocalStepScalar(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.Arm64.ReciprocalStepScalar( + AdvSimd.LoadVector64((Double*)(pFld1)), + AdvSimd.LoadVector64((Double*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ReciprocalStepScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ReciprocalStepScalar( + AdvSimd.LoadVector64((Double*)(&test._fld1)), + AdvSimd.LoadVector64((Double*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + Double[] inArray1 = new Double[Op1ElementCount]; + Double[] inArray2 = new Double[Op2ElementCount]; + Double[] outArray = new Double[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, 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(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Double[] left, Double[] right, Double[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (BitConverter.DoubleToInt64Bits(Helpers.FPRecipStepFused(left[0], right[0])) != BitConverter.DoubleToInt64Bits(result[0])) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (BitConverter.DoubleToInt64Bits(result[i]) != 0) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.ReciprocalStepScalar)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ReciprocalStepScalar.Vector64.Single.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ReciprocalStepScalar.Vector64.Single.cs new file mode 100644 index 00000000000000..3460347beffa90 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ReciprocalStepScalar.Vector64.Single.cs @@ -0,0 +1,537 @@ +// 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.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ReciprocalStepScalar_Vector64_Single() + { + var test = new SimpleBinaryOpTest__ReciprocalStepScalar_Vector64_Single(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + 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__ReciprocalStepScalar_Vector64_Single + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Single[] inArray1, Single[] inArray2, Single[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSingle(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSingle(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ReciprocalStepScalar_Vector64_Single testClass) + { + var result = AdvSimd.Arm64.ReciprocalStepScalar(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ReciprocalStepScalar_Vector64_Single testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.Arm64.ReciprocalStepScalar( + AdvSimd.LoadVector64((Single*)(pFld1)), + AdvSimd.LoadVector64((Single*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Single); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Single); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Single); + + private static Single[] _data1 = new Single[Op1ElementCount]; + private static Single[] _data2 = new Single[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ReciprocalStepScalar_Vector64_Single() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSingle(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSingle(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ReciprocalStepScalar_Vector64_Single() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSingle(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSingle(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSingle(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSingle(); } + _dataTable = new DataTable(_data1, _data2, new Single[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Arm64.ReciprocalStepScalar( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Arm64.ReciprocalStepScalar( + AdvSimd.LoadVector64((Single*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Single*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ReciprocalStepScalar), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ReciprocalStepScalar), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Single*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Single*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Arm64.ReciprocalStepScalar( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.Arm64.ReciprocalStepScalar( + AdvSimd.LoadVector64((Single*)(pClsVar1)), + AdvSimd.LoadVector64((Single*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.Arm64.ReciprocalStepScalar(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Single*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Single*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.Arm64.ReciprocalStepScalar(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ReciprocalStepScalar_Vector64_Single(); + var result = AdvSimd.Arm64.ReciprocalStepScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ReciprocalStepScalar_Vector64_Single(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.Arm64.ReciprocalStepScalar( + AdvSimd.LoadVector64((Single*)(pFld1)), + AdvSimd.LoadVector64((Single*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Arm64.ReciprocalStepScalar(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.Arm64.ReciprocalStepScalar( + AdvSimd.LoadVector64((Single*)(pFld1)), + AdvSimd.LoadVector64((Single*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ReciprocalStepScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ReciprocalStepScalar( + AdvSimd.LoadVector64((Single*)(&test._fld1)), + AdvSimd.LoadVector64((Single*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + Single[] inArray1 = new Single[Op1ElementCount]; + Single[] inArray2 = new Single[Op2ElementCount]; + Single[] outArray = new Single[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, 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(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Single[] left, Single[] right, Single[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (BitConverter.SingleToInt32Bits(Helpers.FPRecipStepFused(left[0], right[0])) != BitConverter.SingleToInt32Bits(result[0])) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (BitConverter.SingleToInt32Bits(result[i]) != 0) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.ReciprocalStepScalar)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AbsoluteDifferenceAdd.Vector128.Byte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AbsoluteDifferenceAdd.Vector128.Byte.cs new file mode 100644 index 00000000000000..651b9221434e66 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AbsoluteDifferenceAdd.Vector128.Byte.cs @@ -0,0 +1,571 @@ +// 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.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AbsoluteDifferenceAdd_Vector128_Byte() + { + var test = new SimpleTernaryOpTest__AbsoluteDifferenceAdd_Vector128_Byte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + 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__AbsoluteDifferenceAdd_Vector128_Byte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] inArray3; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle inHandle3; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Byte[] inArray1, Byte[] inArray2, Byte[] inArray3, Byte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfinArray3 = inArray3.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfinArray3 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.inArray3 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.inHandle3 = GCHandle.Alloc(this.inArray3, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray3Ptr), ref Unsafe.As(ref inArray3[0]), (uint)sizeOfinArray3); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray3Ptr => Align((byte*)(inHandle3.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + inHandle3.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + public Vector128 _fld3; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleTernaryOpTest__AbsoluteDifferenceAdd_Vector128_Byte testClass) + { + var result = AdvSimd.AbsoluteDifferenceAdd(_fld1, _fld2, _fld3); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleTernaryOpTest__AbsoluteDifferenceAdd_Vector128_Byte testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + fixed (Vector128* pFld3 = &_fld3) + { + var result = AdvSimd.AbsoluteDifferenceAdd( + AdvSimd.LoadVector128((Byte*)(pFld1)), + AdvSimd.LoadVector128((Byte*)(pFld2)), + AdvSimd.LoadVector128((Byte*)(pFld3)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int Op3ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / 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 DataTable _dataTable; + + static SimpleTernaryOpTest__AbsoluteDifferenceAdd_Vector128_Byte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleTernaryOpTest__AbsoluteDifferenceAdd_Vector128_Byte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetByte(); } + _dataTable = new DataTable(_data1, _data2, _data3, new Byte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AbsoluteDifferenceAdd( + 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() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AbsoluteDifferenceAdd( + AdvSimd.LoadVector128((Byte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Byte*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector128((Byte*)(_dataTable.inArray3Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AbsoluteDifferenceAdd), 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() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AbsoluteDifferenceAdd), new Type[] { typeof(Vector128), typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Byte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Byte*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector128((Byte*)(_dataTable.inArray3Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AbsoluteDifferenceAdd( + _clsVar1, + _clsVar2, + _clsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + fixed (Vector128* pClsVar3 = &_clsVar3) + { + var result = AdvSimd.AbsoluteDifferenceAdd( + AdvSimd.LoadVector128((Byte*)(pClsVar1)), + AdvSimd.LoadVector128((Byte*)(pClsVar2)), + AdvSimd.LoadVector128((Byte*)(pClsVar3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var op3 = Unsafe.Read>(_dataTable.inArray3Ptr); + var result = AdvSimd.AbsoluteDifferenceAdd(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Byte*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Byte*)(_dataTable.inArray2Ptr)); + var op3 = AdvSimd.LoadVector128((Byte*)(_dataTable.inArray3Ptr)); + var result = AdvSimd.AbsoluteDifferenceAdd(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleTernaryOpTest__AbsoluteDifferenceAdd_Vector128_Byte(); + var result = AdvSimd.AbsoluteDifferenceAdd(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleTernaryOpTest__AbsoluteDifferenceAdd_Vector128_Byte(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + fixed (Vector128* pFld3 = &test._fld3) + { + var result = AdvSimd.AbsoluteDifferenceAdd( + AdvSimd.LoadVector128((Byte*)(pFld1)), + AdvSimd.LoadVector128((Byte*)(pFld2)), + AdvSimd.LoadVector128((Byte*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AbsoluteDifferenceAdd(_fld1, _fld2, _fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + fixed (Vector128* pFld3 = &_fld3) + { + var result = AdvSimd.AbsoluteDifferenceAdd( + AdvSimd.LoadVector128((Byte*)(pFld1)), + AdvSimd.LoadVector128((Byte*)(pFld2)), + AdvSimd.LoadVector128((Byte*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AbsoluteDifferenceAdd(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AbsoluteDifferenceAdd( + AdvSimd.LoadVector128((Byte*)(&test._fld1)), + AdvSimd.LoadVector128((Byte*)(&test._fld2)), + AdvSimd.LoadVector128((Byte*)(&test._fld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, Vector128 op3, 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.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray3[0]), op3); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* op3, 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(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray3[0]), ref Unsafe.AsRef(op3), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(Byte[] firstOp, Byte[] secondOp, Byte[] thirdOp, Byte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AbsoluteDifferenceAdd(firstOp[i], secondOp[i], thirdOp[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AbsoluteDifferenceAdd)}(Vector128, Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($"secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" thirdOp: ({string.Join(", ", thirdOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AbsoluteDifferenceAdd.Vector128.Int16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AbsoluteDifferenceAdd.Vector128.Int16.cs new file mode 100644 index 00000000000000..5ce040c0fb2d95 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AbsoluteDifferenceAdd.Vector128.Int16.cs @@ -0,0 +1,571 @@ +// 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.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AbsoluteDifferenceAdd_Vector128_Int16() + { + var test = new SimpleTernaryOpTest__AbsoluteDifferenceAdd_Vector128_Int16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + 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__AbsoluteDifferenceAdd_Vector128_Int16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] inArray3; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle inHandle3; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray1, Int16[] inArray2, Int16[] inArray3, Int16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfinArray3 = inArray3.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfinArray3 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.inArray3 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.inHandle3 = GCHandle.Alloc(this.inArray3, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray3Ptr), ref Unsafe.As(ref inArray3[0]), (uint)sizeOfinArray3); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray3Ptr => Align((byte*)(inHandle3.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + inHandle3.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + public Vector128 _fld3; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleTernaryOpTest__AbsoluteDifferenceAdd_Vector128_Int16 testClass) + { + var result = AdvSimd.AbsoluteDifferenceAdd(_fld1, _fld2, _fld3); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleTernaryOpTest__AbsoluteDifferenceAdd_Vector128_Int16 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + fixed (Vector128* pFld3 = &_fld3) + { + var result = AdvSimd.AbsoluteDifferenceAdd( + AdvSimd.LoadVector128((Int16*)(pFld1)), + AdvSimd.LoadVector128((Int16*)(pFld2)), + AdvSimd.LoadVector128((Int16*)(pFld3)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int Op3ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + + private static Int16[] _data1 = new Int16[Op1ElementCount]; + private static Int16[] _data2 = new Int16[Op2ElementCount]; + private static Int16[] _data3 = new Int16[Op3ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + private static Vector128 _clsVar3; + + private Vector128 _fld1; + private Vector128 _fld2; + private Vector128 _fld3; + + private DataTable _dataTable; + + static SimpleTernaryOpTest__AbsoluteDifferenceAdd_Vector128_Int16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleTernaryOpTest__AbsoluteDifferenceAdd_Vector128_Int16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data1, _data2, _data3, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AbsoluteDifferenceAdd( + 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() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AbsoluteDifferenceAdd( + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray3Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AbsoluteDifferenceAdd), 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() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AbsoluteDifferenceAdd), new Type[] { typeof(Vector128), typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray3Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AbsoluteDifferenceAdd( + _clsVar1, + _clsVar2, + _clsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + fixed (Vector128* pClsVar3 = &_clsVar3) + { + var result = AdvSimd.AbsoluteDifferenceAdd( + AdvSimd.LoadVector128((Int16*)(pClsVar1)), + AdvSimd.LoadVector128((Int16*)(pClsVar2)), + AdvSimd.LoadVector128((Int16*)(pClsVar3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var op3 = Unsafe.Read>(_dataTable.inArray3Ptr); + var result = AdvSimd.AbsoluteDifferenceAdd(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)); + var op3 = AdvSimd.LoadVector128((Int16*)(_dataTable.inArray3Ptr)); + var result = AdvSimd.AbsoluteDifferenceAdd(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleTernaryOpTest__AbsoluteDifferenceAdd_Vector128_Int16(); + var result = AdvSimd.AbsoluteDifferenceAdd(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleTernaryOpTest__AbsoluteDifferenceAdd_Vector128_Int16(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + fixed (Vector128* pFld3 = &test._fld3) + { + var result = AdvSimd.AbsoluteDifferenceAdd( + AdvSimd.LoadVector128((Int16*)(pFld1)), + AdvSimd.LoadVector128((Int16*)(pFld2)), + AdvSimd.LoadVector128((Int16*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AbsoluteDifferenceAdd(_fld1, _fld2, _fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + fixed (Vector128* pFld3 = &_fld3) + { + var result = AdvSimd.AbsoluteDifferenceAdd( + AdvSimd.LoadVector128((Int16*)(pFld1)), + AdvSimd.LoadVector128((Int16*)(pFld2)), + AdvSimd.LoadVector128((Int16*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AbsoluteDifferenceAdd(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AbsoluteDifferenceAdd( + AdvSimd.LoadVector128((Int16*)(&test._fld1)), + AdvSimd.LoadVector128((Int16*)(&test._fld2)), + AdvSimd.LoadVector128((Int16*)(&test._fld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, Vector128 op3, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int16[] inArray3 = new Int16[Op3ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray3[0]), op3); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* op3, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int16[] inArray3 = new Int16[Op3ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray3[0]), ref Unsafe.AsRef(op3), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(Int16[] firstOp, Int16[] secondOp, Int16[] thirdOp, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AbsoluteDifferenceAdd(firstOp[i], secondOp[i], thirdOp[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AbsoluteDifferenceAdd)}(Vector128, Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($"secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" thirdOp: ({string.Join(", ", thirdOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AbsoluteDifferenceAdd.Vector128.Int32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AbsoluteDifferenceAdd.Vector128.Int32.cs new file mode 100644 index 00000000000000..424a4503214c7b --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AbsoluteDifferenceAdd.Vector128.Int32.cs @@ -0,0 +1,571 @@ +// 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.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AbsoluteDifferenceAdd_Vector128_Int32() + { + var test = new SimpleTernaryOpTest__AbsoluteDifferenceAdd_Vector128_Int32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + 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__AbsoluteDifferenceAdd_Vector128_Int32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] inArray3; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle inHandle3; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray1, Int32[] inArray2, Int32[] inArray3, Int32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfinArray3 = inArray3.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfinArray3 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.inArray3 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.inHandle3 = GCHandle.Alloc(this.inArray3, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray3Ptr), ref Unsafe.As(ref inArray3[0]), (uint)sizeOfinArray3); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray3Ptr => Align((byte*)(inHandle3.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + inHandle3.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + public Vector128 _fld3; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleTernaryOpTest__AbsoluteDifferenceAdd_Vector128_Int32 testClass) + { + var result = AdvSimd.AbsoluteDifferenceAdd(_fld1, _fld2, _fld3); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleTernaryOpTest__AbsoluteDifferenceAdd_Vector128_Int32 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + fixed (Vector128* pFld3 = &_fld3) + { + var result = AdvSimd.AbsoluteDifferenceAdd( + AdvSimd.LoadVector128((Int32*)(pFld1)), + AdvSimd.LoadVector128((Int32*)(pFld2)), + AdvSimd.LoadVector128((Int32*)(pFld3)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int Op3ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + + private static Int32[] _data1 = new Int32[Op1ElementCount]; + private static Int32[] _data2 = new Int32[Op2ElementCount]; + private static Int32[] _data3 = new Int32[Op3ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + private static Vector128 _clsVar3; + + private Vector128 _fld1; + private Vector128 _fld2; + private Vector128 _fld3; + + private DataTable _dataTable; + + static SimpleTernaryOpTest__AbsoluteDifferenceAdd_Vector128_Int32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleTernaryOpTest__AbsoluteDifferenceAdd_Vector128_Int32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data1, _data2, _data3, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AbsoluteDifferenceAdd( + 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() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AbsoluteDifferenceAdd( + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray3Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AbsoluteDifferenceAdd), 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() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AbsoluteDifferenceAdd), new Type[] { typeof(Vector128), typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray3Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AbsoluteDifferenceAdd( + _clsVar1, + _clsVar2, + _clsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + fixed (Vector128* pClsVar3 = &_clsVar3) + { + var result = AdvSimd.AbsoluteDifferenceAdd( + AdvSimd.LoadVector128((Int32*)(pClsVar1)), + AdvSimd.LoadVector128((Int32*)(pClsVar2)), + AdvSimd.LoadVector128((Int32*)(pClsVar3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var op3 = Unsafe.Read>(_dataTable.inArray3Ptr); + var result = AdvSimd.AbsoluteDifferenceAdd(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)); + var op3 = AdvSimd.LoadVector128((Int32*)(_dataTable.inArray3Ptr)); + var result = AdvSimd.AbsoluteDifferenceAdd(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleTernaryOpTest__AbsoluteDifferenceAdd_Vector128_Int32(); + var result = AdvSimd.AbsoluteDifferenceAdd(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleTernaryOpTest__AbsoluteDifferenceAdd_Vector128_Int32(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + fixed (Vector128* pFld3 = &test._fld3) + { + var result = AdvSimd.AbsoluteDifferenceAdd( + AdvSimd.LoadVector128((Int32*)(pFld1)), + AdvSimd.LoadVector128((Int32*)(pFld2)), + AdvSimd.LoadVector128((Int32*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AbsoluteDifferenceAdd(_fld1, _fld2, _fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + fixed (Vector128* pFld3 = &_fld3) + { + var result = AdvSimd.AbsoluteDifferenceAdd( + AdvSimd.LoadVector128((Int32*)(pFld1)), + AdvSimd.LoadVector128((Int32*)(pFld2)), + AdvSimd.LoadVector128((Int32*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AbsoluteDifferenceAdd(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AbsoluteDifferenceAdd( + AdvSimd.LoadVector128((Int32*)(&test._fld1)), + AdvSimd.LoadVector128((Int32*)(&test._fld2)), + AdvSimd.LoadVector128((Int32*)(&test._fld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, Vector128 op3, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] inArray3 = new Int32[Op3ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray3[0]), op3); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* op3, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] inArray3 = new Int32[Op3ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray3[0]), ref Unsafe.AsRef(op3), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(Int32[] firstOp, Int32[] secondOp, Int32[] thirdOp, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AbsoluteDifferenceAdd(firstOp[i], secondOp[i], thirdOp[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AbsoluteDifferenceAdd)}(Vector128, Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($"secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" thirdOp: ({string.Join(", ", thirdOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AbsoluteDifferenceAdd.Vector128.SByte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AbsoluteDifferenceAdd.Vector128.SByte.cs new file mode 100644 index 00000000000000..6975e0c88590c3 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AbsoluteDifferenceAdd.Vector128.SByte.cs @@ -0,0 +1,571 @@ +// 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.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AbsoluteDifferenceAdd_Vector128_SByte() + { + var test = new SimpleTernaryOpTest__AbsoluteDifferenceAdd_Vector128_SByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + 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__AbsoluteDifferenceAdd_Vector128_SByte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] inArray3; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle inHandle3; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(SByte[] inArray1, SByte[] inArray2, SByte[] inArray3, SByte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfinArray3 = inArray3.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfinArray3 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.inArray3 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.inHandle3 = GCHandle.Alloc(this.inArray3, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray3Ptr), ref Unsafe.As(ref inArray3[0]), (uint)sizeOfinArray3); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray3Ptr => Align((byte*)(inHandle3.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + inHandle3.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + public Vector128 _fld3; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleTernaryOpTest__AbsoluteDifferenceAdd_Vector128_SByte testClass) + { + var result = AdvSimd.AbsoluteDifferenceAdd(_fld1, _fld2, _fld3); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleTernaryOpTest__AbsoluteDifferenceAdd_Vector128_SByte testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + fixed (Vector128* pFld3 = &_fld3) + { + var result = AdvSimd.AbsoluteDifferenceAdd( + AdvSimd.LoadVector128((SByte*)(pFld1)), + AdvSimd.LoadVector128((SByte*)(pFld2)), + AdvSimd.LoadVector128((SByte*)(pFld3)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int Op3ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / 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 DataTable _dataTable; + + static SimpleTernaryOpTest__AbsoluteDifferenceAdd_Vector128_SByte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleTernaryOpTest__AbsoluteDifferenceAdd_Vector128_SByte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data1, _data2, _data3, new SByte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AbsoluteDifferenceAdd( + 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() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AbsoluteDifferenceAdd( + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray3Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AbsoluteDifferenceAdd), 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() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AbsoluteDifferenceAdd), new Type[] { typeof(Vector128), typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray3Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AbsoluteDifferenceAdd( + _clsVar1, + _clsVar2, + _clsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + fixed (Vector128* pClsVar3 = &_clsVar3) + { + var result = AdvSimd.AbsoluteDifferenceAdd( + AdvSimd.LoadVector128((SByte*)(pClsVar1)), + AdvSimd.LoadVector128((SByte*)(pClsVar2)), + AdvSimd.LoadVector128((SByte*)(pClsVar3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var op3 = Unsafe.Read>(_dataTable.inArray3Ptr); + var result = AdvSimd.AbsoluteDifferenceAdd(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((SByte*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((SByte*)(_dataTable.inArray2Ptr)); + var op3 = AdvSimd.LoadVector128((SByte*)(_dataTable.inArray3Ptr)); + var result = AdvSimd.AbsoluteDifferenceAdd(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleTernaryOpTest__AbsoluteDifferenceAdd_Vector128_SByte(); + var result = AdvSimd.AbsoluteDifferenceAdd(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleTernaryOpTest__AbsoluteDifferenceAdd_Vector128_SByte(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + fixed (Vector128* pFld3 = &test._fld3) + { + var result = AdvSimd.AbsoluteDifferenceAdd( + AdvSimd.LoadVector128((SByte*)(pFld1)), + AdvSimd.LoadVector128((SByte*)(pFld2)), + AdvSimd.LoadVector128((SByte*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AbsoluteDifferenceAdd(_fld1, _fld2, _fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + fixed (Vector128* pFld3 = &_fld3) + { + var result = AdvSimd.AbsoluteDifferenceAdd( + AdvSimd.LoadVector128((SByte*)(pFld1)), + AdvSimd.LoadVector128((SByte*)(pFld2)), + AdvSimd.LoadVector128((SByte*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AbsoluteDifferenceAdd(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AbsoluteDifferenceAdd( + AdvSimd.LoadVector128((SByte*)(&test._fld1)), + AdvSimd.LoadVector128((SByte*)(&test._fld2)), + AdvSimd.LoadVector128((SByte*)(&test._fld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, Vector128 op3, 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.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray3[0]), op3); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* op3, 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(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray3[0]), ref Unsafe.AsRef(op3), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(SByte[] firstOp, SByte[] secondOp, SByte[] thirdOp, SByte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AbsoluteDifferenceAdd(firstOp[i], secondOp[i], thirdOp[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AbsoluteDifferenceAdd)}(Vector128, Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($"secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" thirdOp: ({string.Join(", ", thirdOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AbsoluteDifferenceAdd.Vector128.UInt16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AbsoluteDifferenceAdd.Vector128.UInt16.cs new file mode 100644 index 00000000000000..086bbbbd20b155 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AbsoluteDifferenceAdd.Vector128.UInt16.cs @@ -0,0 +1,571 @@ +// 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.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AbsoluteDifferenceAdd_Vector128_UInt16() + { + var test = new SimpleTernaryOpTest__AbsoluteDifferenceAdd_Vector128_UInt16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + 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__AbsoluteDifferenceAdd_Vector128_UInt16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] inArray3; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle inHandle3; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt16[] inArray1, UInt16[] inArray2, UInt16[] inArray3, UInt16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfinArray3 = inArray3.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfinArray3 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.inArray3 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.inHandle3 = GCHandle.Alloc(this.inArray3, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray3Ptr), ref Unsafe.As(ref inArray3[0]), (uint)sizeOfinArray3); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray3Ptr => Align((byte*)(inHandle3.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + inHandle3.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + public Vector128 _fld3; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleTernaryOpTest__AbsoluteDifferenceAdd_Vector128_UInt16 testClass) + { + var result = AdvSimd.AbsoluteDifferenceAdd(_fld1, _fld2, _fld3); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleTernaryOpTest__AbsoluteDifferenceAdd_Vector128_UInt16 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + fixed (Vector128* pFld3 = &_fld3) + { + var result = AdvSimd.AbsoluteDifferenceAdd( + AdvSimd.LoadVector128((UInt16*)(pFld1)), + AdvSimd.LoadVector128((UInt16*)(pFld2)), + AdvSimd.LoadVector128((UInt16*)(pFld3)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int Op3ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + + private static UInt16[] _data1 = new UInt16[Op1ElementCount]; + private static UInt16[] _data2 = new UInt16[Op2ElementCount]; + private static UInt16[] _data3 = new UInt16[Op3ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + private static Vector128 _clsVar3; + + private Vector128 _fld1; + private Vector128 _fld2; + private Vector128 _fld3; + + private DataTable _dataTable; + + static SimpleTernaryOpTest__AbsoluteDifferenceAdd_Vector128_UInt16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleTernaryOpTest__AbsoluteDifferenceAdd_Vector128_UInt16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetUInt16(); } + _dataTable = new DataTable(_data1, _data2, _data3, new UInt16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AbsoluteDifferenceAdd( + 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() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AbsoluteDifferenceAdd( + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray3Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AbsoluteDifferenceAdd), 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() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AbsoluteDifferenceAdd), new Type[] { typeof(Vector128), typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray3Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AbsoluteDifferenceAdd( + _clsVar1, + _clsVar2, + _clsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + fixed (Vector128* pClsVar3 = &_clsVar3) + { + var result = AdvSimd.AbsoluteDifferenceAdd( + AdvSimd.LoadVector128((UInt16*)(pClsVar1)), + AdvSimd.LoadVector128((UInt16*)(pClsVar2)), + AdvSimd.LoadVector128((UInt16*)(pClsVar3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var op3 = Unsafe.Read>(_dataTable.inArray3Ptr); + var result = AdvSimd.AbsoluteDifferenceAdd(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)); + var op3 = AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray3Ptr)); + var result = AdvSimd.AbsoluteDifferenceAdd(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleTernaryOpTest__AbsoluteDifferenceAdd_Vector128_UInt16(); + var result = AdvSimd.AbsoluteDifferenceAdd(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleTernaryOpTest__AbsoluteDifferenceAdd_Vector128_UInt16(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + fixed (Vector128* pFld3 = &test._fld3) + { + var result = AdvSimd.AbsoluteDifferenceAdd( + AdvSimd.LoadVector128((UInt16*)(pFld1)), + AdvSimd.LoadVector128((UInt16*)(pFld2)), + AdvSimd.LoadVector128((UInt16*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AbsoluteDifferenceAdd(_fld1, _fld2, _fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + fixed (Vector128* pFld3 = &_fld3) + { + var result = AdvSimd.AbsoluteDifferenceAdd( + AdvSimd.LoadVector128((UInt16*)(pFld1)), + AdvSimd.LoadVector128((UInt16*)(pFld2)), + AdvSimd.LoadVector128((UInt16*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AbsoluteDifferenceAdd(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AbsoluteDifferenceAdd( + AdvSimd.LoadVector128((UInt16*)(&test._fld1)), + AdvSimd.LoadVector128((UInt16*)(&test._fld2)), + AdvSimd.LoadVector128((UInt16*)(&test._fld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, Vector128 op3, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + UInt16[] inArray3 = new UInt16[Op3ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray3[0]), op3); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* op3, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + UInt16[] inArray3 = new UInt16[Op3ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray3[0]), ref Unsafe.AsRef(op3), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(UInt16[] firstOp, UInt16[] secondOp, UInt16[] thirdOp, UInt16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AbsoluteDifferenceAdd(firstOp[i], secondOp[i], thirdOp[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AbsoluteDifferenceAdd)}(Vector128, Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($"secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" thirdOp: ({string.Join(", ", thirdOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AbsoluteDifferenceAdd.Vector128.UInt32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AbsoluteDifferenceAdd.Vector128.UInt32.cs new file mode 100644 index 00000000000000..f6b04bd874da23 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AbsoluteDifferenceAdd.Vector128.UInt32.cs @@ -0,0 +1,571 @@ +// 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.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AbsoluteDifferenceAdd_Vector128_UInt32() + { + var test = new SimpleTernaryOpTest__AbsoluteDifferenceAdd_Vector128_UInt32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + 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__AbsoluteDifferenceAdd_Vector128_UInt32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] inArray3; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle inHandle3; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt32[] inArray1, UInt32[] inArray2, UInt32[] inArray3, UInt32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfinArray3 = inArray3.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfinArray3 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.inArray3 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.inHandle3 = GCHandle.Alloc(this.inArray3, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray3Ptr), ref Unsafe.As(ref inArray3[0]), (uint)sizeOfinArray3); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray3Ptr => Align((byte*)(inHandle3.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + inHandle3.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + public Vector128 _fld3; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleTernaryOpTest__AbsoluteDifferenceAdd_Vector128_UInt32 testClass) + { + var result = AdvSimd.AbsoluteDifferenceAdd(_fld1, _fld2, _fld3); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleTernaryOpTest__AbsoluteDifferenceAdd_Vector128_UInt32 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + fixed (Vector128* pFld3 = &_fld3) + { + var result = AdvSimd.AbsoluteDifferenceAdd( + AdvSimd.LoadVector128((UInt32*)(pFld1)), + AdvSimd.LoadVector128((UInt32*)(pFld2)), + AdvSimd.LoadVector128((UInt32*)(pFld3)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int Op3ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + + private static UInt32[] _data1 = new UInt32[Op1ElementCount]; + private static UInt32[] _data2 = new UInt32[Op2ElementCount]; + private static UInt32[] _data3 = new UInt32[Op3ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + private static Vector128 _clsVar3; + + private Vector128 _fld1; + private Vector128 _fld2; + private Vector128 _fld3; + + private DataTable _dataTable; + + static SimpleTernaryOpTest__AbsoluteDifferenceAdd_Vector128_UInt32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleTernaryOpTest__AbsoluteDifferenceAdd_Vector128_UInt32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetUInt32(); } + _dataTable = new DataTable(_data1, _data2, _data3, new UInt32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AbsoluteDifferenceAdd( + 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() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AbsoluteDifferenceAdd( + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray3Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AbsoluteDifferenceAdd), 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() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AbsoluteDifferenceAdd), new Type[] { typeof(Vector128), typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray3Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AbsoluteDifferenceAdd( + _clsVar1, + _clsVar2, + _clsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + fixed (Vector128* pClsVar3 = &_clsVar3) + { + var result = AdvSimd.AbsoluteDifferenceAdd( + AdvSimd.LoadVector128((UInt32*)(pClsVar1)), + AdvSimd.LoadVector128((UInt32*)(pClsVar2)), + AdvSimd.LoadVector128((UInt32*)(pClsVar3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var op3 = Unsafe.Read>(_dataTable.inArray3Ptr); + var result = AdvSimd.AbsoluteDifferenceAdd(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)); + var op3 = AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray3Ptr)); + var result = AdvSimd.AbsoluteDifferenceAdd(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleTernaryOpTest__AbsoluteDifferenceAdd_Vector128_UInt32(); + var result = AdvSimd.AbsoluteDifferenceAdd(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleTernaryOpTest__AbsoluteDifferenceAdd_Vector128_UInt32(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + fixed (Vector128* pFld3 = &test._fld3) + { + var result = AdvSimd.AbsoluteDifferenceAdd( + AdvSimd.LoadVector128((UInt32*)(pFld1)), + AdvSimd.LoadVector128((UInt32*)(pFld2)), + AdvSimd.LoadVector128((UInt32*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AbsoluteDifferenceAdd(_fld1, _fld2, _fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + fixed (Vector128* pFld3 = &_fld3) + { + var result = AdvSimd.AbsoluteDifferenceAdd( + AdvSimd.LoadVector128((UInt32*)(pFld1)), + AdvSimd.LoadVector128((UInt32*)(pFld2)), + AdvSimd.LoadVector128((UInt32*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AbsoluteDifferenceAdd(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AbsoluteDifferenceAdd( + AdvSimd.LoadVector128((UInt32*)(&test._fld1)), + AdvSimd.LoadVector128((UInt32*)(&test._fld2)), + AdvSimd.LoadVector128((UInt32*)(&test._fld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, Vector128 op3, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt32[] inArray3 = new UInt32[Op3ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray3[0]), op3); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* op3, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt32[] inArray3 = new UInt32[Op3ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray3[0]), ref Unsafe.AsRef(op3), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(UInt32[] firstOp, UInt32[] secondOp, UInt32[] thirdOp, UInt32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AbsoluteDifferenceAdd(firstOp[i], secondOp[i], thirdOp[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AbsoluteDifferenceAdd)}(Vector128, Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($"secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" thirdOp: ({string.Join(", ", thirdOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AbsoluteDifferenceAdd.Vector64.Byte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AbsoluteDifferenceAdd.Vector64.Byte.cs new file mode 100644 index 00000000000000..36b5e668693a69 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AbsoluteDifferenceAdd.Vector64.Byte.cs @@ -0,0 +1,571 @@ +// 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.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AbsoluteDifferenceAdd_Vector64_Byte() + { + var test = new SimpleTernaryOpTest__AbsoluteDifferenceAdd_Vector64_Byte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + 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__AbsoluteDifferenceAdd_Vector64_Byte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] inArray3; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle inHandle3; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Byte[] inArray1, Byte[] inArray2, Byte[] inArray3, Byte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfinArray3 = inArray3.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfinArray3 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.inArray3 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.inHandle3 = GCHandle.Alloc(this.inArray3, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray3Ptr), ref Unsafe.As(ref inArray3[0]), (uint)sizeOfinArray3); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray3Ptr => Align((byte*)(inHandle3.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + inHandle3.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + public Vector64 _fld3; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleTernaryOpTest__AbsoluteDifferenceAdd_Vector64_Byte testClass) + { + var result = AdvSimd.AbsoluteDifferenceAdd(_fld1, _fld2, _fld3); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleTernaryOpTest__AbsoluteDifferenceAdd_Vector64_Byte testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + fixed (Vector64* pFld3 = &_fld3) + { + var result = AdvSimd.AbsoluteDifferenceAdd( + AdvSimd.LoadVector64((Byte*)(pFld1)), + AdvSimd.LoadVector64((Byte*)(pFld2)), + AdvSimd.LoadVector64((Byte*)(pFld3)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int Op3ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / 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 Vector64 _clsVar1; + private static Vector64 _clsVar2; + private static Vector64 _clsVar3; + + private Vector64 _fld1; + private Vector64 _fld2; + private Vector64 _fld3; + + private DataTable _dataTable; + + static SimpleTernaryOpTest__AbsoluteDifferenceAdd_Vector64_Byte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleTernaryOpTest__AbsoluteDifferenceAdd_Vector64_Byte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetByte(); } + _dataTable = new DataTable(_data1, _data2, _data3, new Byte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AbsoluteDifferenceAdd( + 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() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AbsoluteDifferenceAdd( + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray3Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AbsoluteDifferenceAdd), new Type[] { typeof(Vector64), typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AbsoluteDifferenceAdd), new Type[] { typeof(Vector64), typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray3Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AbsoluteDifferenceAdd( + _clsVar1, + _clsVar2, + _clsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + fixed (Vector64* pClsVar3 = &_clsVar3) + { + var result = AdvSimd.AbsoluteDifferenceAdd( + AdvSimd.LoadVector64((Byte*)(pClsVar1)), + AdvSimd.LoadVector64((Byte*)(pClsVar2)), + AdvSimd.LoadVector64((Byte*)(pClsVar3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var op3 = Unsafe.Read>(_dataTable.inArray3Ptr); + var result = AdvSimd.AbsoluteDifferenceAdd(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Byte*)(_dataTable.inArray2Ptr)); + var op3 = AdvSimd.LoadVector64((Byte*)(_dataTable.inArray3Ptr)); + var result = AdvSimd.AbsoluteDifferenceAdd(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleTernaryOpTest__AbsoluteDifferenceAdd_Vector64_Byte(); + var result = AdvSimd.AbsoluteDifferenceAdd(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleTernaryOpTest__AbsoluteDifferenceAdd_Vector64_Byte(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + fixed (Vector64* pFld3 = &test._fld3) + { + var result = AdvSimd.AbsoluteDifferenceAdd( + AdvSimd.LoadVector64((Byte*)(pFld1)), + AdvSimd.LoadVector64((Byte*)(pFld2)), + AdvSimd.LoadVector64((Byte*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AbsoluteDifferenceAdd(_fld1, _fld2, _fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + fixed (Vector64* pFld3 = &_fld3) + { + var result = AdvSimd.AbsoluteDifferenceAdd( + AdvSimd.LoadVector64((Byte*)(pFld1)), + AdvSimd.LoadVector64((Byte*)(pFld2)), + AdvSimd.LoadVector64((Byte*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AbsoluteDifferenceAdd(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AbsoluteDifferenceAdd( + AdvSimd.LoadVector64((Byte*)(&test._fld1)), + AdvSimd.LoadVector64((Byte*)(&test._fld2)), + AdvSimd.LoadVector64((Byte*)(&test._fld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, Vector64 op3, 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.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray3[0]), op3); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* op3, 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(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray3[0]), ref Unsafe.AsRef(op3), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(Byte[] firstOp, Byte[] secondOp, Byte[] thirdOp, Byte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AbsoluteDifferenceAdd(firstOp[i], secondOp[i], thirdOp[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AbsoluteDifferenceAdd)}(Vector64, Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($"secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" thirdOp: ({string.Join(", ", thirdOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AbsoluteDifferenceAdd.Vector64.Int16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AbsoluteDifferenceAdd.Vector64.Int16.cs new file mode 100644 index 00000000000000..77b6bd22f7f9d7 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AbsoluteDifferenceAdd.Vector64.Int16.cs @@ -0,0 +1,571 @@ +// 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.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AbsoluteDifferenceAdd_Vector64_Int16() + { + var test = new SimpleTernaryOpTest__AbsoluteDifferenceAdd_Vector64_Int16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + 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__AbsoluteDifferenceAdd_Vector64_Int16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] inArray3; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle inHandle3; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray1, Int16[] inArray2, Int16[] inArray3, Int16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfinArray3 = inArray3.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfinArray3 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.inArray3 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.inHandle3 = GCHandle.Alloc(this.inArray3, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray3Ptr), ref Unsafe.As(ref inArray3[0]), (uint)sizeOfinArray3); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray3Ptr => Align((byte*)(inHandle3.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + inHandle3.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + public Vector64 _fld3; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleTernaryOpTest__AbsoluteDifferenceAdd_Vector64_Int16 testClass) + { + var result = AdvSimd.AbsoluteDifferenceAdd(_fld1, _fld2, _fld3); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleTernaryOpTest__AbsoluteDifferenceAdd_Vector64_Int16 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + fixed (Vector64* pFld3 = &_fld3) + { + var result = AdvSimd.AbsoluteDifferenceAdd( + AdvSimd.LoadVector64((Int16*)(pFld1)), + AdvSimd.LoadVector64((Int16*)(pFld2)), + AdvSimd.LoadVector64((Int16*)(pFld3)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int Op3ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + + private static Int16[] _data1 = new Int16[Op1ElementCount]; + private static Int16[] _data2 = new Int16[Op2ElementCount]; + private static Int16[] _data3 = new Int16[Op3ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + private static Vector64 _clsVar3; + + private Vector64 _fld1; + private Vector64 _fld2; + private Vector64 _fld3; + + private DataTable _dataTable; + + static SimpleTernaryOpTest__AbsoluteDifferenceAdd_Vector64_Int16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleTernaryOpTest__AbsoluteDifferenceAdd_Vector64_Int16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data1, _data2, _data3, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AbsoluteDifferenceAdd( + 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() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AbsoluteDifferenceAdd( + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray3Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AbsoluteDifferenceAdd), new Type[] { typeof(Vector64), typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AbsoluteDifferenceAdd), new Type[] { typeof(Vector64), typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray3Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AbsoluteDifferenceAdd( + _clsVar1, + _clsVar2, + _clsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + fixed (Vector64* pClsVar3 = &_clsVar3) + { + var result = AdvSimd.AbsoluteDifferenceAdd( + AdvSimd.LoadVector64((Int16*)(pClsVar1)), + AdvSimd.LoadVector64((Int16*)(pClsVar2)), + AdvSimd.LoadVector64((Int16*)(pClsVar3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var op3 = Unsafe.Read>(_dataTable.inArray3Ptr); + var result = AdvSimd.AbsoluteDifferenceAdd(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)); + var op3 = AdvSimd.LoadVector64((Int16*)(_dataTable.inArray3Ptr)); + var result = AdvSimd.AbsoluteDifferenceAdd(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleTernaryOpTest__AbsoluteDifferenceAdd_Vector64_Int16(); + var result = AdvSimd.AbsoluteDifferenceAdd(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleTernaryOpTest__AbsoluteDifferenceAdd_Vector64_Int16(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + fixed (Vector64* pFld3 = &test._fld3) + { + var result = AdvSimd.AbsoluteDifferenceAdd( + AdvSimd.LoadVector64((Int16*)(pFld1)), + AdvSimd.LoadVector64((Int16*)(pFld2)), + AdvSimd.LoadVector64((Int16*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AbsoluteDifferenceAdd(_fld1, _fld2, _fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + fixed (Vector64* pFld3 = &_fld3) + { + var result = AdvSimd.AbsoluteDifferenceAdd( + AdvSimd.LoadVector64((Int16*)(pFld1)), + AdvSimd.LoadVector64((Int16*)(pFld2)), + AdvSimd.LoadVector64((Int16*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AbsoluteDifferenceAdd(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AbsoluteDifferenceAdd( + AdvSimd.LoadVector64((Int16*)(&test._fld1)), + AdvSimd.LoadVector64((Int16*)(&test._fld2)), + AdvSimd.LoadVector64((Int16*)(&test._fld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, Vector64 op3, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int16[] inArray3 = new Int16[Op3ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray3[0]), op3); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* op3, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int16[] inArray3 = new Int16[Op3ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray3[0]), ref Unsafe.AsRef(op3), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(Int16[] firstOp, Int16[] secondOp, Int16[] thirdOp, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AbsoluteDifferenceAdd(firstOp[i], secondOp[i], thirdOp[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AbsoluteDifferenceAdd)}(Vector64, Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($"secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" thirdOp: ({string.Join(", ", thirdOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AbsoluteDifferenceAdd.Vector64.Int32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AbsoluteDifferenceAdd.Vector64.Int32.cs new file mode 100644 index 00000000000000..e75afed56bb2a2 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AbsoluteDifferenceAdd.Vector64.Int32.cs @@ -0,0 +1,571 @@ +// 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.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AbsoluteDifferenceAdd_Vector64_Int32() + { + var test = new SimpleTernaryOpTest__AbsoluteDifferenceAdd_Vector64_Int32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + 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__AbsoluteDifferenceAdd_Vector64_Int32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] inArray3; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle inHandle3; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray1, Int32[] inArray2, Int32[] inArray3, Int32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfinArray3 = inArray3.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfinArray3 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.inArray3 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.inHandle3 = GCHandle.Alloc(this.inArray3, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray3Ptr), ref Unsafe.As(ref inArray3[0]), (uint)sizeOfinArray3); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray3Ptr => Align((byte*)(inHandle3.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + inHandle3.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + public Vector64 _fld3; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleTernaryOpTest__AbsoluteDifferenceAdd_Vector64_Int32 testClass) + { + var result = AdvSimd.AbsoluteDifferenceAdd(_fld1, _fld2, _fld3); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleTernaryOpTest__AbsoluteDifferenceAdd_Vector64_Int32 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + fixed (Vector64* pFld3 = &_fld3) + { + var result = AdvSimd.AbsoluteDifferenceAdd( + AdvSimd.LoadVector64((Int32*)(pFld1)), + AdvSimd.LoadVector64((Int32*)(pFld2)), + AdvSimd.LoadVector64((Int32*)(pFld3)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int Op3ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + + private static Int32[] _data1 = new Int32[Op1ElementCount]; + private static Int32[] _data2 = new Int32[Op2ElementCount]; + private static Int32[] _data3 = new Int32[Op3ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + private static Vector64 _clsVar3; + + private Vector64 _fld1; + private Vector64 _fld2; + private Vector64 _fld3; + + private DataTable _dataTable; + + static SimpleTernaryOpTest__AbsoluteDifferenceAdd_Vector64_Int32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleTernaryOpTest__AbsoluteDifferenceAdd_Vector64_Int32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data1, _data2, _data3, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AbsoluteDifferenceAdd( + 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() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AbsoluteDifferenceAdd( + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray3Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AbsoluteDifferenceAdd), new Type[] { typeof(Vector64), typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AbsoluteDifferenceAdd), new Type[] { typeof(Vector64), typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray3Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AbsoluteDifferenceAdd( + _clsVar1, + _clsVar2, + _clsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + fixed (Vector64* pClsVar3 = &_clsVar3) + { + var result = AdvSimd.AbsoluteDifferenceAdd( + AdvSimd.LoadVector64((Int32*)(pClsVar1)), + AdvSimd.LoadVector64((Int32*)(pClsVar2)), + AdvSimd.LoadVector64((Int32*)(pClsVar3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var op3 = Unsafe.Read>(_dataTable.inArray3Ptr); + var result = AdvSimd.AbsoluteDifferenceAdd(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)); + var op3 = AdvSimd.LoadVector64((Int32*)(_dataTable.inArray3Ptr)); + var result = AdvSimd.AbsoluteDifferenceAdd(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleTernaryOpTest__AbsoluteDifferenceAdd_Vector64_Int32(); + var result = AdvSimd.AbsoluteDifferenceAdd(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleTernaryOpTest__AbsoluteDifferenceAdd_Vector64_Int32(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + fixed (Vector64* pFld3 = &test._fld3) + { + var result = AdvSimd.AbsoluteDifferenceAdd( + AdvSimd.LoadVector64((Int32*)(pFld1)), + AdvSimd.LoadVector64((Int32*)(pFld2)), + AdvSimd.LoadVector64((Int32*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AbsoluteDifferenceAdd(_fld1, _fld2, _fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + fixed (Vector64* pFld3 = &_fld3) + { + var result = AdvSimd.AbsoluteDifferenceAdd( + AdvSimd.LoadVector64((Int32*)(pFld1)), + AdvSimd.LoadVector64((Int32*)(pFld2)), + AdvSimd.LoadVector64((Int32*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AbsoluteDifferenceAdd(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AbsoluteDifferenceAdd( + AdvSimd.LoadVector64((Int32*)(&test._fld1)), + AdvSimd.LoadVector64((Int32*)(&test._fld2)), + AdvSimd.LoadVector64((Int32*)(&test._fld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, Vector64 op3, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] inArray3 = new Int32[Op3ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray3[0]), op3); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* op3, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] inArray3 = new Int32[Op3ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray3[0]), ref Unsafe.AsRef(op3), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(Int32[] firstOp, Int32[] secondOp, Int32[] thirdOp, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AbsoluteDifferenceAdd(firstOp[i], secondOp[i], thirdOp[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AbsoluteDifferenceAdd)}(Vector64, Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($"secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" thirdOp: ({string.Join(", ", thirdOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AbsoluteDifferenceAdd.Vector64.SByte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AbsoluteDifferenceAdd.Vector64.SByte.cs new file mode 100644 index 00000000000000..d904b29bf20842 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AbsoluteDifferenceAdd.Vector64.SByte.cs @@ -0,0 +1,571 @@ +// 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.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AbsoluteDifferenceAdd_Vector64_SByte() + { + var test = new SimpleTernaryOpTest__AbsoluteDifferenceAdd_Vector64_SByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + 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__AbsoluteDifferenceAdd_Vector64_SByte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] inArray3; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle inHandle3; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(SByte[] inArray1, SByte[] inArray2, SByte[] inArray3, SByte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfinArray3 = inArray3.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfinArray3 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.inArray3 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.inHandle3 = GCHandle.Alloc(this.inArray3, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray3Ptr), ref Unsafe.As(ref inArray3[0]), (uint)sizeOfinArray3); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray3Ptr => Align((byte*)(inHandle3.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + inHandle3.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + public Vector64 _fld3; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleTernaryOpTest__AbsoluteDifferenceAdd_Vector64_SByte testClass) + { + var result = AdvSimd.AbsoluteDifferenceAdd(_fld1, _fld2, _fld3); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleTernaryOpTest__AbsoluteDifferenceAdd_Vector64_SByte testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + fixed (Vector64* pFld3 = &_fld3) + { + var result = AdvSimd.AbsoluteDifferenceAdd( + AdvSimd.LoadVector64((SByte*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)), + AdvSimd.LoadVector64((SByte*)(pFld3)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int Op3ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / 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 Vector64 _clsVar1; + private static Vector64 _clsVar2; + private static Vector64 _clsVar3; + + private Vector64 _fld1; + private Vector64 _fld2; + private Vector64 _fld3; + + private DataTable _dataTable; + + static SimpleTernaryOpTest__AbsoluteDifferenceAdd_Vector64_SByte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleTernaryOpTest__AbsoluteDifferenceAdd_Vector64_SByte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data1, _data2, _data3, new SByte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AbsoluteDifferenceAdd( + 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() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AbsoluteDifferenceAdd( + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray3Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AbsoluteDifferenceAdd), new Type[] { typeof(Vector64), typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AbsoluteDifferenceAdd), new Type[] { typeof(Vector64), typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray3Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AbsoluteDifferenceAdd( + _clsVar1, + _clsVar2, + _clsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + fixed (Vector64* pClsVar3 = &_clsVar3) + { + var result = AdvSimd.AbsoluteDifferenceAdd( + AdvSimd.LoadVector64((SByte*)(pClsVar1)), + AdvSimd.LoadVector64((SByte*)(pClsVar2)), + AdvSimd.LoadVector64((SByte*)(pClsVar3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var op3 = Unsafe.Read>(_dataTable.inArray3Ptr); + var result = AdvSimd.AbsoluteDifferenceAdd(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)); + var op3 = AdvSimd.LoadVector64((SByte*)(_dataTable.inArray3Ptr)); + var result = AdvSimd.AbsoluteDifferenceAdd(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleTernaryOpTest__AbsoluteDifferenceAdd_Vector64_SByte(); + var result = AdvSimd.AbsoluteDifferenceAdd(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleTernaryOpTest__AbsoluteDifferenceAdd_Vector64_SByte(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + fixed (Vector64* pFld3 = &test._fld3) + { + var result = AdvSimd.AbsoluteDifferenceAdd( + AdvSimd.LoadVector64((SByte*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)), + AdvSimd.LoadVector64((SByte*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AbsoluteDifferenceAdd(_fld1, _fld2, _fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + fixed (Vector64* pFld3 = &_fld3) + { + var result = AdvSimd.AbsoluteDifferenceAdd( + AdvSimd.LoadVector64((SByte*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)), + AdvSimd.LoadVector64((SByte*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AbsoluteDifferenceAdd(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AbsoluteDifferenceAdd( + AdvSimd.LoadVector64((SByte*)(&test._fld1)), + AdvSimd.LoadVector64((SByte*)(&test._fld2)), + AdvSimd.LoadVector64((SByte*)(&test._fld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, Vector64 op3, 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.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray3[0]), op3); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* op3, 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(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray3[0]), ref Unsafe.AsRef(op3), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(SByte[] firstOp, SByte[] secondOp, SByte[] thirdOp, SByte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AbsoluteDifferenceAdd(firstOp[i], secondOp[i], thirdOp[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AbsoluteDifferenceAdd)}(Vector64, Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($"secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" thirdOp: ({string.Join(", ", thirdOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AbsoluteDifferenceAdd.Vector64.UInt16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AbsoluteDifferenceAdd.Vector64.UInt16.cs new file mode 100644 index 00000000000000..ab321fc1a08d72 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AbsoluteDifferenceAdd.Vector64.UInt16.cs @@ -0,0 +1,571 @@ +// 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.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AbsoluteDifferenceAdd_Vector64_UInt16() + { + var test = new SimpleTernaryOpTest__AbsoluteDifferenceAdd_Vector64_UInt16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + 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__AbsoluteDifferenceAdd_Vector64_UInt16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] inArray3; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle inHandle3; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt16[] inArray1, UInt16[] inArray2, UInt16[] inArray3, UInt16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfinArray3 = inArray3.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfinArray3 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.inArray3 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.inHandle3 = GCHandle.Alloc(this.inArray3, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray3Ptr), ref Unsafe.As(ref inArray3[0]), (uint)sizeOfinArray3); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray3Ptr => Align((byte*)(inHandle3.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + inHandle3.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + public Vector64 _fld3; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleTernaryOpTest__AbsoluteDifferenceAdd_Vector64_UInt16 testClass) + { + var result = AdvSimd.AbsoluteDifferenceAdd(_fld1, _fld2, _fld3); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleTernaryOpTest__AbsoluteDifferenceAdd_Vector64_UInt16 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + fixed (Vector64* pFld3 = &_fld3) + { + var result = AdvSimd.AbsoluteDifferenceAdd( + AdvSimd.LoadVector64((UInt16*)(pFld1)), + AdvSimd.LoadVector64((UInt16*)(pFld2)), + AdvSimd.LoadVector64((UInt16*)(pFld3)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int Op3ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + + private static UInt16[] _data1 = new UInt16[Op1ElementCount]; + private static UInt16[] _data2 = new UInt16[Op2ElementCount]; + private static UInt16[] _data3 = new UInt16[Op3ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + private static Vector64 _clsVar3; + + private Vector64 _fld1; + private Vector64 _fld2; + private Vector64 _fld3; + + private DataTable _dataTable; + + static SimpleTernaryOpTest__AbsoluteDifferenceAdd_Vector64_UInt16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleTernaryOpTest__AbsoluteDifferenceAdd_Vector64_UInt16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetUInt16(); } + _dataTable = new DataTable(_data1, _data2, _data3, new UInt16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AbsoluteDifferenceAdd( + 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() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AbsoluteDifferenceAdd( + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray3Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AbsoluteDifferenceAdd), new Type[] { typeof(Vector64), typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AbsoluteDifferenceAdd), new Type[] { typeof(Vector64), typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray3Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AbsoluteDifferenceAdd( + _clsVar1, + _clsVar2, + _clsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + fixed (Vector64* pClsVar3 = &_clsVar3) + { + var result = AdvSimd.AbsoluteDifferenceAdd( + AdvSimd.LoadVector64((UInt16*)(pClsVar1)), + AdvSimd.LoadVector64((UInt16*)(pClsVar2)), + AdvSimd.LoadVector64((UInt16*)(pClsVar3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var op3 = Unsafe.Read>(_dataTable.inArray3Ptr); + var result = AdvSimd.AbsoluteDifferenceAdd(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray2Ptr)); + var op3 = AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray3Ptr)); + var result = AdvSimd.AbsoluteDifferenceAdd(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleTernaryOpTest__AbsoluteDifferenceAdd_Vector64_UInt16(); + var result = AdvSimd.AbsoluteDifferenceAdd(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleTernaryOpTest__AbsoluteDifferenceAdd_Vector64_UInt16(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + fixed (Vector64* pFld3 = &test._fld3) + { + var result = AdvSimd.AbsoluteDifferenceAdd( + AdvSimd.LoadVector64((UInt16*)(pFld1)), + AdvSimd.LoadVector64((UInt16*)(pFld2)), + AdvSimd.LoadVector64((UInt16*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AbsoluteDifferenceAdd(_fld1, _fld2, _fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + fixed (Vector64* pFld3 = &_fld3) + { + var result = AdvSimd.AbsoluteDifferenceAdd( + AdvSimd.LoadVector64((UInt16*)(pFld1)), + AdvSimd.LoadVector64((UInt16*)(pFld2)), + AdvSimd.LoadVector64((UInt16*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AbsoluteDifferenceAdd(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AbsoluteDifferenceAdd( + AdvSimd.LoadVector64((UInt16*)(&test._fld1)), + AdvSimd.LoadVector64((UInt16*)(&test._fld2)), + AdvSimd.LoadVector64((UInt16*)(&test._fld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, Vector64 op3, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + UInt16[] inArray3 = new UInt16[Op3ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray3[0]), op3); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* op3, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + UInt16[] inArray3 = new UInt16[Op3ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray3[0]), ref Unsafe.AsRef(op3), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(UInt16[] firstOp, UInt16[] secondOp, UInt16[] thirdOp, UInt16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AbsoluteDifferenceAdd(firstOp[i], secondOp[i], thirdOp[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AbsoluteDifferenceAdd)}(Vector64, Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($"secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" thirdOp: ({string.Join(", ", thirdOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AbsoluteDifferenceAdd.Vector64.UInt32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AbsoluteDifferenceAdd.Vector64.UInt32.cs new file mode 100644 index 00000000000000..61a4c21c7c4386 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AbsoluteDifferenceAdd.Vector64.UInt32.cs @@ -0,0 +1,571 @@ +// 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.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AbsoluteDifferenceAdd_Vector64_UInt32() + { + var test = new SimpleTernaryOpTest__AbsoluteDifferenceAdd_Vector64_UInt32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + 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__AbsoluteDifferenceAdd_Vector64_UInt32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] inArray3; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle inHandle3; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt32[] inArray1, UInt32[] inArray2, UInt32[] inArray3, UInt32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfinArray3 = inArray3.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfinArray3 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.inArray3 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.inHandle3 = GCHandle.Alloc(this.inArray3, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray3Ptr), ref Unsafe.As(ref inArray3[0]), (uint)sizeOfinArray3); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray3Ptr => Align((byte*)(inHandle3.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + inHandle3.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + public Vector64 _fld3; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleTernaryOpTest__AbsoluteDifferenceAdd_Vector64_UInt32 testClass) + { + var result = AdvSimd.AbsoluteDifferenceAdd(_fld1, _fld2, _fld3); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleTernaryOpTest__AbsoluteDifferenceAdd_Vector64_UInt32 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + fixed (Vector64* pFld3 = &_fld3) + { + var result = AdvSimd.AbsoluteDifferenceAdd( + AdvSimd.LoadVector64((UInt32*)(pFld1)), + AdvSimd.LoadVector64((UInt32*)(pFld2)), + AdvSimd.LoadVector64((UInt32*)(pFld3)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int Op3ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + + private static UInt32[] _data1 = new UInt32[Op1ElementCount]; + private static UInt32[] _data2 = new UInt32[Op2ElementCount]; + private static UInt32[] _data3 = new UInt32[Op3ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + private static Vector64 _clsVar3; + + private Vector64 _fld1; + private Vector64 _fld2; + private Vector64 _fld3; + + private DataTable _dataTable; + + static SimpleTernaryOpTest__AbsoluteDifferenceAdd_Vector64_UInt32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleTernaryOpTest__AbsoluteDifferenceAdd_Vector64_UInt32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetUInt32(); } + _dataTable = new DataTable(_data1, _data2, _data3, new UInt32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AbsoluteDifferenceAdd( + 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() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AbsoluteDifferenceAdd( + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray3Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AbsoluteDifferenceAdd), new Type[] { typeof(Vector64), typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AbsoluteDifferenceAdd), new Type[] { typeof(Vector64), typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray3Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AbsoluteDifferenceAdd( + _clsVar1, + _clsVar2, + _clsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + fixed (Vector64* pClsVar3 = &_clsVar3) + { + var result = AdvSimd.AbsoluteDifferenceAdd( + AdvSimd.LoadVector64((UInt32*)(pClsVar1)), + AdvSimd.LoadVector64((UInt32*)(pClsVar2)), + AdvSimd.LoadVector64((UInt32*)(pClsVar3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var op3 = Unsafe.Read>(_dataTable.inArray3Ptr); + var result = AdvSimd.AbsoluteDifferenceAdd(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray2Ptr)); + var op3 = AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray3Ptr)); + var result = AdvSimd.AbsoluteDifferenceAdd(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleTernaryOpTest__AbsoluteDifferenceAdd_Vector64_UInt32(); + var result = AdvSimd.AbsoluteDifferenceAdd(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleTernaryOpTest__AbsoluteDifferenceAdd_Vector64_UInt32(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + fixed (Vector64* pFld3 = &test._fld3) + { + var result = AdvSimd.AbsoluteDifferenceAdd( + AdvSimd.LoadVector64((UInt32*)(pFld1)), + AdvSimd.LoadVector64((UInt32*)(pFld2)), + AdvSimd.LoadVector64((UInt32*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AbsoluteDifferenceAdd(_fld1, _fld2, _fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + fixed (Vector64* pFld3 = &_fld3) + { + var result = AdvSimd.AbsoluteDifferenceAdd( + AdvSimd.LoadVector64((UInt32*)(pFld1)), + AdvSimd.LoadVector64((UInt32*)(pFld2)), + AdvSimd.LoadVector64((UInt32*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AbsoluteDifferenceAdd(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AbsoluteDifferenceAdd( + AdvSimd.LoadVector64((UInt32*)(&test._fld1)), + AdvSimd.LoadVector64((UInt32*)(&test._fld2)), + AdvSimd.LoadVector64((UInt32*)(&test._fld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, Vector64 op3, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt32[] inArray3 = new UInt32[Op3ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray3[0]), op3); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* op3, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt32[] inArray3 = new UInt32[Op3ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray3[0]), ref Unsafe.AsRef(op3), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(UInt32[] firstOp, UInt32[] secondOp, UInt32[] thirdOp, UInt32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AbsoluteDifferenceAdd(firstOp[i], secondOp[i], thirdOp[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AbsoluteDifferenceAdd)}(Vector64, Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($"secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" thirdOp: ({string.Join(", ", thirdOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AdvSimd_r.csproj b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AdvSimd_r.csproj index 07a3c5940f5531..568d0ed667be2c 100644 --- a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AdvSimd_r.csproj +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AdvSimd_r.csproj @@ -40,6 +40,18 @@ + + + + + + + + + + + + @@ -423,10 +435,26 @@ + + + + + + + + + + + + + + + + diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AdvSimd_ro.csproj b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AdvSimd_ro.csproj index 10562a585f1869..b2dc6750343071 100644 --- a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AdvSimd_ro.csproj +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AdvSimd_ro.csproj @@ -40,6 +40,18 @@ + + + + + + + + + + + + @@ -423,10 +435,26 @@ + + + + + + + + + + + + + + + + diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/PolynomialMultiply.Vector128.Byte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/PolynomialMultiply.Vector128.Byte.cs new file mode 100644 index 00000000000000..163a9a380b6bc0 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/PolynomialMultiply.Vector128.Byte.cs @@ -0,0 +1,530 @@ +// 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.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void PolynomialMultiply_Vector128_Byte() + { + var test = new SimpleBinaryOpTest__PolynomialMultiply_Vector128_Byte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + 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__PolynomialMultiply_Vector128_Byte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Byte[] inArray1, Byte[] inArray2, Byte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__PolynomialMultiply_Vector128_Byte testClass) + { + var result = AdvSimd.PolynomialMultiply(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__PolynomialMultiply_Vector128_Byte testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.PolynomialMultiply( + AdvSimd.LoadVector128((Byte*)(pFld1)), + AdvSimd.LoadVector128((Byte*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / 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 DataTable _dataTable; + + static SimpleBinaryOpTest__PolynomialMultiply_Vector128_Byte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__PolynomialMultiply_Vector128_Byte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + _dataTable = new DataTable(_data1, _data2, new Byte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.PolynomialMultiply( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.PolynomialMultiply( + AdvSimd.LoadVector128((Byte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Byte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.PolynomialMultiply), 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() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.PolynomialMultiply), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Byte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Byte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.PolynomialMultiply( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.PolynomialMultiply( + AdvSimd.LoadVector128((Byte*)(pClsVar1)), + AdvSimd.LoadVector128((Byte*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.PolynomialMultiply(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Byte*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Byte*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.PolynomialMultiply(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__PolynomialMultiply_Vector128_Byte(); + var result = AdvSimd.PolynomialMultiply(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__PolynomialMultiply_Vector128_Byte(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.PolynomialMultiply( + AdvSimd.LoadVector128((Byte*)(pFld1)), + AdvSimd.LoadVector128((Byte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.PolynomialMultiply(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.PolynomialMultiply( + AdvSimd.LoadVector128((Byte*)(pFld1)), + AdvSimd.LoadVector128((Byte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.PolynomialMultiply(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.PolynomialMultiply( + AdvSimd.LoadVector128((Byte*)(&test._fld1)), + AdvSimd.LoadVector128((Byte*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + Byte[] inArray2 = new Byte[Op2ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + Byte[] inArray2 = new Byte[Op2ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Byte[] left, Byte[] right, Byte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.PolynomialMultiply(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.PolynomialMultiply)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/PolynomialMultiply.Vector128.SByte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/PolynomialMultiply.Vector128.SByte.cs new file mode 100644 index 00000000000000..9ef67979da5d6a --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/PolynomialMultiply.Vector128.SByte.cs @@ -0,0 +1,530 @@ +// 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.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void PolynomialMultiply_Vector128_SByte() + { + var test = new SimpleBinaryOpTest__PolynomialMultiply_Vector128_SByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + 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__PolynomialMultiply_Vector128_SByte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(SByte[] inArray1, SByte[] inArray2, SByte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__PolynomialMultiply_Vector128_SByte testClass) + { + var result = AdvSimd.PolynomialMultiply(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__PolynomialMultiply_Vector128_SByte testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.PolynomialMultiply( + AdvSimd.LoadVector128((SByte*)(pFld1)), + AdvSimd.LoadVector128((SByte*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / 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 DataTable _dataTable; + + static SimpleBinaryOpTest__PolynomialMultiply_Vector128_SByte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__PolynomialMultiply_Vector128_SByte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data1, _data2, new SByte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.PolynomialMultiply( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.PolynomialMultiply( + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.PolynomialMultiply), 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() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.PolynomialMultiply), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.PolynomialMultiply( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.PolynomialMultiply( + AdvSimd.LoadVector128((SByte*)(pClsVar1)), + AdvSimd.LoadVector128((SByte*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.PolynomialMultiply(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((SByte*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((SByte*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.PolynomialMultiply(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__PolynomialMultiply_Vector128_SByte(); + var result = AdvSimd.PolynomialMultiply(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__PolynomialMultiply_Vector128_SByte(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.PolynomialMultiply( + AdvSimd.LoadVector128((SByte*)(pFld1)), + AdvSimd.LoadVector128((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.PolynomialMultiply(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.PolynomialMultiply( + AdvSimd.LoadVector128((SByte*)(pFld1)), + AdvSimd.LoadVector128((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.PolynomialMultiply(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.PolynomialMultiply( + AdvSimd.LoadVector128((SByte*)(&test._fld1)), + AdvSimd.LoadVector128((SByte*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, 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(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(SByte[] left, SByte[] right, SByte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.PolynomialMultiply(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.PolynomialMultiply)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/PolynomialMultiply.Vector64.Byte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/PolynomialMultiply.Vector64.Byte.cs new file mode 100644 index 00000000000000..bb2a1dcc342134 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/PolynomialMultiply.Vector64.Byte.cs @@ -0,0 +1,530 @@ +// 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.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void PolynomialMultiply_Vector64_Byte() + { + var test = new SimpleBinaryOpTest__PolynomialMultiply_Vector64_Byte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + 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__PolynomialMultiply_Vector64_Byte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Byte[] inArray1, Byte[] inArray2, Byte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__PolynomialMultiply_Vector64_Byte testClass) + { + var result = AdvSimd.PolynomialMultiply(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__PolynomialMultiply_Vector64_Byte testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.PolynomialMultiply( + AdvSimd.LoadVector64((Byte*)(pFld1)), + AdvSimd.LoadVector64((Byte*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Byte); + + private static Byte[] _data1 = new Byte[Op1ElementCount]; + private static Byte[] _data2 = new Byte[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__PolynomialMultiply_Vector64_Byte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__PolynomialMultiply_Vector64_Byte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + _dataTable = new DataTable(_data1, _data2, new Byte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.PolynomialMultiply( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.PolynomialMultiply( + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.PolynomialMultiply), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.PolynomialMultiply), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.PolynomialMultiply( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.PolynomialMultiply( + AdvSimd.LoadVector64((Byte*)(pClsVar1)), + AdvSimd.LoadVector64((Byte*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.PolynomialMultiply(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Byte*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.PolynomialMultiply(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__PolynomialMultiply_Vector64_Byte(); + var result = AdvSimd.PolynomialMultiply(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__PolynomialMultiply_Vector64_Byte(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.PolynomialMultiply( + AdvSimd.LoadVector64((Byte*)(pFld1)), + AdvSimd.LoadVector64((Byte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.PolynomialMultiply(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.PolynomialMultiply( + AdvSimd.LoadVector64((Byte*)(pFld1)), + AdvSimd.LoadVector64((Byte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.PolynomialMultiply(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.PolynomialMultiply( + AdvSimd.LoadVector64((Byte*)(&test._fld1)), + AdvSimd.LoadVector64((Byte*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + Byte[] inArray2 = new Byte[Op2ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + Byte[] inArray2 = new Byte[Op2ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Byte[] left, Byte[] right, Byte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.PolynomialMultiply(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.PolynomialMultiply)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/PolynomialMultiply.Vector64.SByte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/PolynomialMultiply.Vector64.SByte.cs new file mode 100644 index 00000000000000..1118db8fb19050 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/PolynomialMultiply.Vector64.SByte.cs @@ -0,0 +1,530 @@ +// 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.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void PolynomialMultiply_Vector64_SByte() + { + var test = new SimpleBinaryOpTest__PolynomialMultiply_Vector64_SByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + 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__PolynomialMultiply_Vector64_SByte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(SByte[] inArray1, SByte[] inArray2, SByte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__PolynomialMultiply_Vector64_SByte testClass) + { + var result = AdvSimd.PolynomialMultiply(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__PolynomialMultiply_Vector64_SByte testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.PolynomialMultiply( + AdvSimd.LoadVector64((SByte*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(SByte); + + private static SByte[] _data1 = new SByte[Op1ElementCount]; + private static SByte[] _data2 = new SByte[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__PolynomialMultiply_Vector64_SByte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__PolynomialMultiply_Vector64_SByte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data1, _data2, new SByte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.PolynomialMultiply( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.PolynomialMultiply( + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.PolynomialMultiply), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.PolynomialMultiply), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.PolynomialMultiply( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.PolynomialMultiply( + AdvSimd.LoadVector64((SByte*)(pClsVar1)), + AdvSimd.LoadVector64((SByte*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.PolynomialMultiply(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.PolynomialMultiply(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__PolynomialMultiply_Vector64_SByte(); + var result = AdvSimd.PolynomialMultiply(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__PolynomialMultiply_Vector64_SByte(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.PolynomialMultiply( + AdvSimd.LoadVector64((SByte*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.PolynomialMultiply(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.PolynomialMultiply( + AdvSimd.LoadVector64((SByte*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.PolynomialMultiply(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.PolynomialMultiply( + AdvSimd.LoadVector64((SByte*)(&test._fld1)), + AdvSimd.LoadVector64((SByte*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, 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(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(SByte[] left, SByte[] right, SByte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.PolynomialMultiply(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.PolynomialMultiply)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Program.AdvSimd.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Program.AdvSimd.cs index dd20b98214422b..f290a7c489cba7 100644 --- a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Program.AdvSimd.cs +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Program.AdvSimd.cs @@ -44,6 +44,18 @@ static Program() ["AbsoluteDifference.Vector128.Single"] = AbsoluteDifference_Vector128_Single, ["AbsoluteDifference.Vector128.UInt16"] = AbsoluteDifference_Vector128_UInt16, ["AbsoluteDifference.Vector128.UInt32"] = AbsoluteDifference_Vector128_UInt32, + ["AbsoluteDifferenceAdd.Vector64.Byte"] = AbsoluteDifferenceAdd_Vector64_Byte, + ["AbsoluteDifferenceAdd.Vector64.Int16"] = AbsoluteDifferenceAdd_Vector64_Int16, + ["AbsoluteDifferenceAdd.Vector64.Int32"] = AbsoluteDifferenceAdd_Vector64_Int32, + ["AbsoluteDifferenceAdd.Vector64.SByte"] = AbsoluteDifferenceAdd_Vector64_SByte, + ["AbsoluteDifferenceAdd.Vector64.UInt16"] = AbsoluteDifferenceAdd_Vector64_UInt16, + ["AbsoluteDifferenceAdd.Vector64.UInt32"] = AbsoluteDifferenceAdd_Vector64_UInt32, + ["AbsoluteDifferenceAdd.Vector128.Byte"] = AbsoluteDifferenceAdd_Vector128_Byte, + ["AbsoluteDifferenceAdd.Vector128.Int16"] = AbsoluteDifferenceAdd_Vector128_Int16, + ["AbsoluteDifferenceAdd.Vector128.Int32"] = AbsoluteDifferenceAdd_Vector128_Int32, + ["AbsoluteDifferenceAdd.Vector128.SByte"] = AbsoluteDifferenceAdd_Vector128_SByte, + ["AbsoluteDifferenceAdd.Vector128.UInt16"] = AbsoluteDifferenceAdd_Vector128_UInt16, + ["AbsoluteDifferenceAdd.Vector128.UInt32"] = AbsoluteDifferenceAdd_Vector128_UInt32, ["Add.Vector64.Byte"] = Add_Vector64_Byte, ["Add.Vector64.Int16"] = Add_Vector64_Int16, ["Add.Vector64.Int32"] = Add_Vector64_Int32, @@ -427,10 +439,26 @@ static Program() ["OrNot.Vector128.UInt16"] = OrNot_Vector128_UInt16, ["OrNot.Vector128.UInt32"] = OrNot_Vector128_UInt32, ["OrNot.Vector128.UInt64"] = OrNot_Vector128_UInt64, + ["PolynomialMultiply.Vector64.Byte"] = PolynomialMultiply_Vector64_Byte, + ["PolynomialMultiply.Vector64.SByte"] = PolynomialMultiply_Vector64_SByte, + ["PolynomialMultiply.Vector128.Byte"] = PolynomialMultiply_Vector128_Byte, + ["PolynomialMultiply.Vector128.SByte"] = PolynomialMultiply_Vector128_SByte, ["PopCount.Vector64.Byte"] = PopCount_Vector64_Byte, ["PopCount.Vector64.SByte"] = PopCount_Vector64_SByte, ["PopCount.Vector128.Byte"] = PopCount_Vector128_Byte, ["PopCount.Vector128.SByte"] = PopCount_Vector128_SByte, + ["ReciprocalEstimate.Vector64.Single"] = ReciprocalEstimate_Vector64_Single, + ["ReciprocalEstimate.Vector64.UInt32"] = ReciprocalEstimate_Vector64_UInt32, + ["ReciprocalEstimate.Vector128.Single"] = ReciprocalEstimate_Vector128_Single, + ["ReciprocalEstimate.Vector128.UInt32"] = ReciprocalEstimate_Vector128_UInt32, + ["ReciprocalSquareRootEstimate.Vector64.Single"] = ReciprocalSquareRootEstimate_Vector64_Single, + ["ReciprocalSquareRootEstimate.Vector64.UInt32"] = ReciprocalSquareRootEstimate_Vector64_UInt32, + ["ReciprocalSquareRootEstimate.Vector128.Single"] = ReciprocalSquareRootEstimate_Vector128_Single, + ["ReciprocalSquareRootEstimate.Vector128.UInt32"] = ReciprocalSquareRootEstimate_Vector128_UInt32, + ["ReciprocalSquareRootStep.Vector64.Single"] = ReciprocalSquareRootStep_Vector64_Single, + ["ReciprocalSquareRootStep.Vector128.Single"] = ReciprocalSquareRootStep_Vector128_Single, + ["ReciprocalStep.Vector64.Single"] = ReciprocalStep_Vector64_Single, + ["ReciprocalStep.Vector128.Single"] = ReciprocalStep_Vector128_Single, ["SqrtScalar.Vector64.Double"] = SqrtScalar_Vector64_Double, ["SqrtScalar.Vector64.Single"] = SqrtScalar_Vector64_Single, ["Subtract.Vector64.Byte"] = Subtract_Vector64_Byte, diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ReciprocalEstimate.Vector128.Single.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ReciprocalEstimate.Vector128.Single.cs new file mode 100644 index 00000000000000..bd27567ae8e71d --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ReciprocalEstimate.Vector128.Single.cs @@ -0,0 +1,489 @@ +// 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.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ReciprocalEstimate_Vector128_Single() + { + var test = new SimpleUnaryOpTest__ReciprocalEstimate_Vector128_Single(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + 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__ReciprocalEstimate_Vector128_Single + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Single[] inArray1, Single[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = BitConverter.Int32BitsToSingle(0x3e4ed9ed); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleUnaryOpTest__ReciprocalEstimate_Vector128_Single testClass) + { + var result = AdvSimd.ReciprocalEstimate(_fld1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleUnaryOpTest__ReciprocalEstimate_Vector128_Single testClass) + { + fixed (Vector128* pFld1 = &_fld1) + { + var result = AdvSimd.ReciprocalEstimate( + AdvSimd.LoadVector128((Single*)(pFld1)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Single); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Single); + + private static Single[] _data1 = new Single[Op1ElementCount]; + + private static Vector128 _clsVar1; + + private Vector128 _fld1; + + private DataTable _dataTable; + + static SimpleUnaryOpTest__ReciprocalEstimate_Vector128_Single() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = BitConverter.Int32BitsToSingle(0x3e4ed9ed); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleUnaryOpTest__ReciprocalEstimate_Vector128_Single() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = BitConverter.Int32BitsToSingle(0x3e4ed9ed); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = BitConverter.Int32BitsToSingle(0x3e4ed9ed); } + _dataTable = new DataTable(_data1, new Single[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ReciprocalEstimate( + Unsafe.Read>(_dataTable.inArray1Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ReciprocalEstimate( + AdvSimd.LoadVector128((Single*)(_dataTable.inArray1Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ReciprocalEstimate), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ReciprocalEstimate), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Single*)(_dataTable.inArray1Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ReciprocalEstimate( + _clsVar1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + { + var result = AdvSimd.ReciprocalEstimate( + AdvSimd.LoadVector128((Single*)(pClsVar1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var result = AdvSimd.ReciprocalEstimate(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Single*)(_dataTable.inArray1Ptr)); + var result = AdvSimd.ReciprocalEstimate(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleUnaryOpTest__ReciprocalEstimate_Vector128_Single(); + var result = AdvSimd.ReciprocalEstimate(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleUnaryOpTest__ReciprocalEstimate_Vector128_Single(); + + fixed (Vector128* pFld1 = &test._fld1) + { + var result = AdvSimd.ReciprocalEstimate( + AdvSimd.LoadVector128((Single*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ReciprocalEstimate(_fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + { + var result = AdvSimd.ReciprocalEstimate( + AdvSimd.LoadVector128((Single*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ReciprocalEstimate(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ReciprocalEstimate( + AdvSimd.LoadVector128((Single*)(&test._fld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, void* result, [CallerMemberName] string method = "") + { + Single[] inArray1 = new Single[Op1ElementCount]; + Single[] outArray = new Single[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(void* op1, void* result, [CallerMemberName] string method = "") + { + Single[] inArray1 = new Single[Op1ElementCount]; + Single[] outArray = new Single[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(Single[] firstOp, Single[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (BitConverter.SingleToInt32Bits(result[i]) != 0x409e8000) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ReciprocalEstimate)}(Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ReciprocalEstimate.Vector128.UInt32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ReciprocalEstimate.Vector128.UInt32.cs new file mode 100644 index 00000000000000..4f778234aff838 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ReciprocalEstimate.Vector128.UInt32.cs @@ -0,0 +1,489 @@ +// 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.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ReciprocalEstimate_Vector128_UInt32() + { + var test = new SimpleUnaryOpTest__ReciprocalEstimate_Vector128_UInt32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + 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__ReciprocalEstimate_Vector128_UInt32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt32[] inArray1, UInt32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleUnaryOpTest__ReciprocalEstimate_Vector128_UInt32 testClass) + { + var result = AdvSimd.ReciprocalEstimate(_fld1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleUnaryOpTest__ReciprocalEstimate_Vector128_UInt32 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + { + var result = AdvSimd.ReciprocalEstimate( + AdvSimd.LoadVector128((UInt32*)(pFld1)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + + private static UInt32[] _data1 = new UInt32[Op1ElementCount]; + + private static Vector128 _clsVar1; + + private Vector128 _fld1; + + private DataTable _dataTable; + + static SimpleUnaryOpTest__ReciprocalEstimate_Vector128_UInt32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleUnaryOpTest__ReciprocalEstimate_Vector128_UInt32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + _dataTable = new DataTable(_data1, new UInt32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ReciprocalEstimate( + Unsafe.Read>(_dataTable.inArray1Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ReciprocalEstimate( + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ReciprocalEstimate), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ReciprocalEstimate), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ReciprocalEstimate( + _clsVar1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + { + var result = AdvSimd.ReciprocalEstimate( + AdvSimd.LoadVector128((UInt32*)(pClsVar1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var result = AdvSimd.ReciprocalEstimate(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)); + var result = AdvSimd.ReciprocalEstimate(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleUnaryOpTest__ReciprocalEstimate_Vector128_UInt32(); + var result = AdvSimd.ReciprocalEstimate(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleUnaryOpTest__ReciprocalEstimate_Vector128_UInt32(); + + fixed (Vector128* pFld1 = &test._fld1) + { + var result = AdvSimd.ReciprocalEstimate( + AdvSimd.LoadVector128((UInt32*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ReciprocalEstimate(_fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + { + var result = AdvSimd.ReciprocalEstimate( + AdvSimd.LoadVector128((UInt32*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ReciprocalEstimate(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ReciprocalEstimate( + AdvSimd.LoadVector128((UInt32*)(&test._fld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(void* op1, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(UInt32[] firstOp, UInt32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.UnsignedRecipEstimate(firstOp[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ReciprocalEstimate)}(Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ReciprocalEstimate.Vector64.Single.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ReciprocalEstimate.Vector64.Single.cs new file mode 100644 index 00000000000000..29df4edff0a362 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ReciprocalEstimate.Vector64.Single.cs @@ -0,0 +1,489 @@ +// 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.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ReciprocalEstimate_Vector64_Single() + { + var test = new SimpleUnaryOpTest__ReciprocalEstimate_Vector64_Single(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + 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__ReciprocalEstimate_Vector64_Single + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Single[] inArray1, Single[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = BitConverter.Int32BitsToSingle(0x3e4ed9ed); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleUnaryOpTest__ReciprocalEstimate_Vector64_Single testClass) + { + var result = AdvSimd.ReciprocalEstimate(_fld1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleUnaryOpTest__ReciprocalEstimate_Vector64_Single testClass) + { + fixed (Vector64* pFld1 = &_fld1) + { + var result = AdvSimd.ReciprocalEstimate( + AdvSimd.LoadVector64((Single*)(pFld1)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Single); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Single); + + private static Single[] _data1 = new Single[Op1ElementCount]; + + private static Vector64 _clsVar1; + + private Vector64 _fld1; + + private DataTable _dataTable; + + static SimpleUnaryOpTest__ReciprocalEstimate_Vector64_Single() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = BitConverter.Int32BitsToSingle(0x3e4ed9ed); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleUnaryOpTest__ReciprocalEstimate_Vector64_Single() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = BitConverter.Int32BitsToSingle(0x3e4ed9ed); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = BitConverter.Int32BitsToSingle(0x3e4ed9ed); } + _dataTable = new DataTable(_data1, new Single[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ReciprocalEstimate( + Unsafe.Read>(_dataTable.inArray1Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ReciprocalEstimate( + AdvSimd.LoadVector64((Single*)(_dataTable.inArray1Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ReciprocalEstimate), new Type[] { typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ReciprocalEstimate), new Type[] { typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Single*)(_dataTable.inArray1Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ReciprocalEstimate( + _clsVar1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + { + var result = AdvSimd.ReciprocalEstimate( + AdvSimd.LoadVector64((Single*)(pClsVar1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var result = AdvSimd.ReciprocalEstimate(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Single*)(_dataTable.inArray1Ptr)); + var result = AdvSimd.ReciprocalEstimate(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleUnaryOpTest__ReciprocalEstimate_Vector64_Single(); + var result = AdvSimd.ReciprocalEstimate(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleUnaryOpTest__ReciprocalEstimate_Vector64_Single(); + + fixed (Vector64* pFld1 = &test._fld1) + { + var result = AdvSimd.ReciprocalEstimate( + AdvSimd.LoadVector64((Single*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ReciprocalEstimate(_fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + { + var result = AdvSimd.ReciprocalEstimate( + AdvSimd.LoadVector64((Single*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ReciprocalEstimate(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ReciprocalEstimate( + AdvSimd.LoadVector64((Single*)(&test._fld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, void* result, [CallerMemberName] string method = "") + { + Single[] inArray1 = new Single[Op1ElementCount]; + Single[] outArray = new Single[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(void* op1, void* result, [CallerMemberName] string method = "") + { + Single[] inArray1 = new Single[Op1ElementCount]; + Single[] outArray = new Single[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(Single[] firstOp, Single[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (BitConverter.SingleToInt32Bits(result[i]) != 0x409e8000) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ReciprocalEstimate)}(Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ReciprocalEstimate.Vector64.UInt32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ReciprocalEstimate.Vector64.UInt32.cs new file mode 100644 index 00000000000000..6a676efab8beaa --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ReciprocalEstimate.Vector64.UInt32.cs @@ -0,0 +1,489 @@ +// 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.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ReciprocalEstimate_Vector64_UInt32() + { + var test = new SimpleUnaryOpTest__ReciprocalEstimate_Vector64_UInt32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + 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__ReciprocalEstimate_Vector64_UInt32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt32[] inArray1, UInt32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleUnaryOpTest__ReciprocalEstimate_Vector64_UInt32 testClass) + { + var result = AdvSimd.ReciprocalEstimate(_fld1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleUnaryOpTest__ReciprocalEstimate_Vector64_UInt32 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + { + var result = AdvSimd.ReciprocalEstimate( + AdvSimd.LoadVector64((UInt32*)(pFld1)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + + private static UInt32[] _data1 = new UInt32[Op1ElementCount]; + + private static Vector64 _clsVar1; + + private Vector64 _fld1; + + private DataTable _dataTable; + + static SimpleUnaryOpTest__ReciprocalEstimate_Vector64_UInt32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleUnaryOpTest__ReciprocalEstimate_Vector64_UInt32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + _dataTable = new DataTable(_data1, new UInt32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ReciprocalEstimate( + Unsafe.Read>(_dataTable.inArray1Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ReciprocalEstimate( + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ReciprocalEstimate), new Type[] { typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ReciprocalEstimate), new Type[] { typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ReciprocalEstimate( + _clsVar1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + { + var result = AdvSimd.ReciprocalEstimate( + AdvSimd.LoadVector64((UInt32*)(pClsVar1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var result = AdvSimd.ReciprocalEstimate(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)); + var result = AdvSimd.ReciprocalEstimate(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleUnaryOpTest__ReciprocalEstimate_Vector64_UInt32(); + var result = AdvSimd.ReciprocalEstimate(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleUnaryOpTest__ReciprocalEstimate_Vector64_UInt32(); + + fixed (Vector64* pFld1 = &test._fld1) + { + var result = AdvSimd.ReciprocalEstimate( + AdvSimd.LoadVector64((UInt32*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ReciprocalEstimate(_fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + { + var result = AdvSimd.ReciprocalEstimate( + AdvSimd.LoadVector64((UInt32*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ReciprocalEstimate(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ReciprocalEstimate( + AdvSimd.LoadVector64((UInt32*)(&test._fld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(void* op1, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(UInt32[] firstOp, UInt32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.UnsignedRecipEstimate(firstOp[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ReciprocalEstimate)}(Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ReciprocalSquareRootEstimate.Vector128.Single.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ReciprocalSquareRootEstimate.Vector128.Single.cs new file mode 100644 index 00000000000000..10b80e42fb033a --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ReciprocalSquareRootEstimate.Vector128.Single.cs @@ -0,0 +1,489 @@ +// 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.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ReciprocalSquareRootEstimate_Vector128_Single() + { + var test = new SimpleUnaryOpTest__ReciprocalSquareRootEstimate_Vector128_Single(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + 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__ReciprocalSquareRootEstimate_Vector128_Single + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Single[] inArray1, Single[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = BitConverter.Int32BitsToSingle(0x3e4ed9ed); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleUnaryOpTest__ReciprocalSquareRootEstimate_Vector128_Single testClass) + { + var result = AdvSimd.ReciprocalSquareRootEstimate(_fld1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleUnaryOpTest__ReciprocalSquareRootEstimate_Vector128_Single testClass) + { + fixed (Vector128* pFld1 = &_fld1) + { + var result = AdvSimd.ReciprocalSquareRootEstimate( + AdvSimd.LoadVector128((Single*)(pFld1)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Single); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Single); + + private static Single[] _data1 = new Single[Op1ElementCount]; + + private static Vector128 _clsVar1; + + private Vector128 _fld1; + + private DataTable _dataTable; + + static SimpleUnaryOpTest__ReciprocalSquareRootEstimate_Vector128_Single() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = BitConverter.Int32BitsToSingle(0x3e4ed9ed); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleUnaryOpTest__ReciprocalSquareRootEstimate_Vector128_Single() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = BitConverter.Int32BitsToSingle(0x3e4ed9ed); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = BitConverter.Int32BitsToSingle(0x3e4ed9ed); } + _dataTable = new DataTable(_data1, new Single[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ReciprocalSquareRootEstimate( + Unsafe.Read>(_dataTable.inArray1Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ReciprocalSquareRootEstimate( + AdvSimd.LoadVector128((Single*)(_dataTable.inArray1Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ReciprocalSquareRootEstimate), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ReciprocalSquareRootEstimate), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Single*)(_dataTable.inArray1Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ReciprocalSquareRootEstimate( + _clsVar1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + { + var result = AdvSimd.ReciprocalSquareRootEstimate( + AdvSimd.LoadVector128((Single*)(pClsVar1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var result = AdvSimd.ReciprocalSquareRootEstimate(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Single*)(_dataTable.inArray1Ptr)); + var result = AdvSimd.ReciprocalSquareRootEstimate(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleUnaryOpTest__ReciprocalSquareRootEstimate_Vector128_Single(); + var result = AdvSimd.ReciprocalSquareRootEstimate(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleUnaryOpTest__ReciprocalSquareRootEstimate_Vector128_Single(); + + fixed (Vector128* pFld1 = &test._fld1) + { + var result = AdvSimd.ReciprocalSquareRootEstimate( + AdvSimd.LoadVector128((Single*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ReciprocalSquareRootEstimate(_fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + { + var result = AdvSimd.ReciprocalSquareRootEstimate( + AdvSimd.LoadVector128((Single*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ReciprocalSquareRootEstimate(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ReciprocalSquareRootEstimate( + AdvSimd.LoadVector128((Single*)(&test._fld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, void* result, [CallerMemberName] string method = "") + { + Single[] inArray1 = new Single[Op1ElementCount]; + Single[] outArray = new Single[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(void* op1, void* result, [CallerMemberName] string method = "") + { + Single[] inArray1 = new Single[Op1ElementCount]; + Single[] outArray = new Single[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(Single[] firstOp, Single[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (BitConverter.SingleToInt32Bits(result[i]) != 0x400e8000) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ReciprocalSquareRootEstimate)}(Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ReciprocalSquareRootEstimate.Vector128.UInt32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ReciprocalSquareRootEstimate.Vector128.UInt32.cs new file mode 100644 index 00000000000000..4549371a696242 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ReciprocalSquareRootEstimate.Vector128.UInt32.cs @@ -0,0 +1,489 @@ +// 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.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ReciprocalSquareRootEstimate_Vector128_UInt32() + { + var test = new SimpleUnaryOpTest__ReciprocalSquareRootEstimate_Vector128_UInt32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + 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__ReciprocalSquareRootEstimate_Vector128_UInt32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt32[] inArray1, UInt32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleUnaryOpTest__ReciprocalSquareRootEstimate_Vector128_UInt32 testClass) + { + var result = AdvSimd.ReciprocalSquareRootEstimate(_fld1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleUnaryOpTest__ReciprocalSquareRootEstimate_Vector128_UInt32 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + { + var result = AdvSimd.ReciprocalSquareRootEstimate( + AdvSimd.LoadVector128((UInt32*)(pFld1)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + + private static UInt32[] _data1 = new UInt32[Op1ElementCount]; + + private static Vector128 _clsVar1; + + private Vector128 _fld1; + + private DataTable _dataTable; + + static SimpleUnaryOpTest__ReciprocalSquareRootEstimate_Vector128_UInt32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleUnaryOpTest__ReciprocalSquareRootEstimate_Vector128_UInt32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + _dataTable = new DataTable(_data1, new UInt32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ReciprocalSquareRootEstimate( + Unsafe.Read>(_dataTable.inArray1Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ReciprocalSquareRootEstimate( + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ReciprocalSquareRootEstimate), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ReciprocalSquareRootEstimate), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ReciprocalSquareRootEstimate( + _clsVar1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + { + var result = AdvSimd.ReciprocalSquareRootEstimate( + AdvSimd.LoadVector128((UInt32*)(pClsVar1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var result = AdvSimd.ReciprocalSquareRootEstimate(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)); + var result = AdvSimd.ReciprocalSquareRootEstimate(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleUnaryOpTest__ReciprocalSquareRootEstimate_Vector128_UInt32(); + var result = AdvSimd.ReciprocalSquareRootEstimate(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleUnaryOpTest__ReciprocalSquareRootEstimate_Vector128_UInt32(); + + fixed (Vector128* pFld1 = &test._fld1) + { + var result = AdvSimd.ReciprocalSquareRootEstimate( + AdvSimd.LoadVector128((UInt32*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ReciprocalSquareRootEstimate(_fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + { + var result = AdvSimd.ReciprocalSquareRootEstimate( + AdvSimd.LoadVector128((UInt32*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ReciprocalSquareRootEstimate(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ReciprocalSquareRootEstimate( + AdvSimd.LoadVector128((UInt32*)(&test._fld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(void* op1, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(UInt32[] firstOp, UInt32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.UnsignedRSqrtEstimate(firstOp[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ReciprocalSquareRootEstimate)}(Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ReciprocalSquareRootEstimate.Vector64.Single.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ReciprocalSquareRootEstimate.Vector64.Single.cs new file mode 100644 index 00000000000000..ed335787fe7453 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ReciprocalSquareRootEstimate.Vector64.Single.cs @@ -0,0 +1,489 @@ +// 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.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ReciprocalSquareRootEstimate_Vector64_Single() + { + var test = new SimpleUnaryOpTest__ReciprocalSquareRootEstimate_Vector64_Single(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + 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__ReciprocalSquareRootEstimate_Vector64_Single + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Single[] inArray1, Single[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = BitConverter.Int32BitsToSingle(0x3e4ed9ed); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleUnaryOpTest__ReciprocalSquareRootEstimate_Vector64_Single testClass) + { + var result = AdvSimd.ReciprocalSquareRootEstimate(_fld1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleUnaryOpTest__ReciprocalSquareRootEstimate_Vector64_Single testClass) + { + fixed (Vector64* pFld1 = &_fld1) + { + var result = AdvSimd.ReciprocalSquareRootEstimate( + AdvSimd.LoadVector64((Single*)(pFld1)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Single); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Single); + + private static Single[] _data1 = new Single[Op1ElementCount]; + + private static Vector64 _clsVar1; + + private Vector64 _fld1; + + private DataTable _dataTable; + + static SimpleUnaryOpTest__ReciprocalSquareRootEstimate_Vector64_Single() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = BitConverter.Int32BitsToSingle(0x3e4ed9ed); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleUnaryOpTest__ReciprocalSquareRootEstimate_Vector64_Single() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = BitConverter.Int32BitsToSingle(0x3e4ed9ed); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = BitConverter.Int32BitsToSingle(0x3e4ed9ed); } + _dataTable = new DataTable(_data1, new Single[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ReciprocalSquareRootEstimate( + Unsafe.Read>(_dataTable.inArray1Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ReciprocalSquareRootEstimate( + AdvSimd.LoadVector64((Single*)(_dataTable.inArray1Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ReciprocalSquareRootEstimate), new Type[] { typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ReciprocalSquareRootEstimate), new Type[] { typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Single*)(_dataTable.inArray1Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ReciprocalSquareRootEstimate( + _clsVar1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + { + var result = AdvSimd.ReciprocalSquareRootEstimate( + AdvSimd.LoadVector64((Single*)(pClsVar1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var result = AdvSimd.ReciprocalSquareRootEstimate(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Single*)(_dataTable.inArray1Ptr)); + var result = AdvSimd.ReciprocalSquareRootEstimate(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleUnaryOpTest__ReciprocalSquareRootEstimate_Vector64_Single(); + var result = AdvSimd.ReciprocalSquareRootEstimate(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleUnaryOpTest__ReciprocalSquareRootEstimate_Vector64_Single(); + + fixed (Vector64* pFld1 = &test._fld1) + { + var result = AdvSimd.ReciprocalSquareRootEstimate( + AdvSimd.LoadVector64((Single*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ReciprocalSquareRootEstimate(_fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + { + var result = AdvSimd.ReciprocalSquareRootEstimate( + AdvSimd.LoadVector64((Single*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ReciprocalSquareRootEstimate(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ReciprocalSquareRootEstimate( + AdvSimd.LoadVector64((Single*)(&test._fld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, void* result, [CallerMemberName] string method = "") + { + Single[] inArray1 = new Single[Op1ElementCount]; + Single[] outArray = new Single[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(void* op1, void* result, [CallerMemberName] string method = "") + { + Single[] inArray1 = new Single[Op1ElementCount]; + Single[] outArray = new Single[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(Single[] firstOp, Single[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (BitConverter.SingleToInt32Bits(result[i]) != 0x400e8000) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ReciprocalSquareRootEstimate)}(Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ReciprocalSquareRootEstimate.Vector64.UInt32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ReciprocalSquareRootEstimate.Vector64.UInt32.cs new file mode 100644 index 00000000000000..eb8360cd71803c --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ReciprocalSquareRootEstimate.Vector64.UInt32.cs @@ -0,0 +1,489 @@ +// 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.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ReciprocalSquareRootEstimate_Vector64_UInt32() + { + var test = new SimpleUnaryOpTest__ReciprocalSquareRootEstimate_Vector64_UInt32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + 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__ReciprocalSquareRootEstimate_Vector64_UInt32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt32[] inArray1, UInt32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleUnaryOpTest__ReciprocalSquareRootEstimate_Vector64_UInt32 testClass) + { + var result = AdvSimd.ReciprocalSquareRootEstimate(_fld1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleUnaryOpTest__ReciprocalSquareRootEstimate_Vector64_UInt32 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + { + var result = AdvSimd.ReciprocalSquareRootEstimate( + AdvSimd.LoadVector64((UInt32*)(pFld1)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + + private static UInt32[] _data1 = new UInt32[Op1ElementCount]; + + private static Vector64 _clsVar1; + + private Vector64 _fld1; + + private DataTable _dataTable; + + static SimpleUnaryOpTest__ReciprocalSquareRootEstimate_Vector64_UInt32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleUnaryOpTest__ReciprocalSquareRootEstimate_Vector64_UInt32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + _dataTable = new DataTable(_data1, new UInt32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ReciprocalSquareRootEstimate( + Unsafe.Read>(_dataTable.inArray1Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ReciprocalSquareRootEstimate( + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ReciprocalSquareRootEstimate), new Type[] { typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ReciprocalSquareRootEstimate), new Type[] { typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ReciprocalSquareRootEstimate( + _clsVar1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + { + var result = AdvSimd.ReciprocalSquareRootEstimate( + AdvSimd.LoadVector64((UInt32*)(pClsVar1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var result = AdvSimd.ReciprocalSquareRootEstimate(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)); + var result = AdvSimd.ReciprocalSquareRootEstimate(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleUnaryOpTest__ReciprocalSquareRootEstimate_Vector64_UInt32(); + var result = AdvSimd.ReciprocalSquareRootEstimate(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleUnaryOpTest__ReciprocalSquareRootEstimate_Vector64_UInt32(); + + fixed (Vector64* pFld1 = &test._fld1) + { + var result = AdvSimd.ReciprocalSquareRootEstimate( + AdvSimd.LoadVector64((UInt32*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ReciprocalSquareRootEstimate(_fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + { + var result = AdvSimd.ReciprocalSquareRootEstimate( + AdvSimd.LoadVector64((UInt32*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ReciprocalSquareRootEstimate(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ReciprocalSquareRootEstimate( + AdvSimd.LoadVector64((UInt32*)(&test._fld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(void* op1, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(UInt32[] firstOp, UInt32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.UnsignedRSqrtEstimate(firstOp[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ReciprocalSquareRootEstimate)}(Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ReciprocalSquareRootStep.Vector128.Single.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ReciprocalSquareRootStep.Vector128.Single.cs new file mode 100644 index 00000000000000..d44ce5a00ed210 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ReciprocalSquareRootStep.Vector128.Single.cs @@ -0,0 +1,530 @@ +// 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.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ReciprocalSquareRootStep_Vector128_Single() + { + var test = new SimpleBinaryOpTest__ReciprocalSquareRootStep_Vector128_Single(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + 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__ReciprocalSquareRootStep_Vector128_Single + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Single[] inArray1, Single[] inArray2, Single[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSingle(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSingle(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ReciprocalSquareRootStep_Vector128_Single testClass) + { + var result = AdvSimd.ReciprocalSquareRootStep(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ReciprocalSquareRootStep_Vector128_Single testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ReciprocalSquareRootStep( + AdvSimd.LoadVector128((Single*)(pFld1)), + AdvSimd.LoadVector128((Single*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Single); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Single); + private static readonly int RetElementCount = Unsafe.SizeOf>() / 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 DataTable _dataTable; + + static SimpleBinaryOpTest__ReciprocalSquareRootStep_Vector128_Single() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSingle(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSingle(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ReciprocalSquareRootStep_Vector128_Single() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSingle(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSingle(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSingle(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSingle(); } + _dataTable = new DataTable(_data1, _data2, new Single[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ReciprocalSquareRootStep( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ReciprocalSquareRootStep( + AdvSimd.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ReciprocalSquareRootStep), 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() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ReciprocalSquareRootStep), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ReciprocalSquareRootStep( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ReciprocalSquareRootStep( + AdvSimd.LoadVector128((Single*)(pClsVar1)), + AdvSimd.LoadVector128((Single*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ReciprocalSquareRootStep(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Single*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Single*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ReciprocalSquareRootStep(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ReciprocalSquareRootStep_Vector128_Single(); + var result = AdvSimd.ReciprocalSquareRootStep(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ReciprocalSquareRootStep_Vector128_Single(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.ReciprocalSquareRootStep( + AdvSimd.LoadVector128((Single*)(pFld1)), + AdvSimd.LoadVector128((Single*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ReciprocalSquareRootStep(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ReciprocalSquareRootStep( + AdvSimd.LoadVector128((Single*)(pFld1)), + AdvSimd.LoadVector128((Single*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ReciprocalSquareRootStep(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ReciprocalSquareRootStep( + AdvSimd.LoadVector128((Single*)(&test._fld1)), + AdvSimd.LoadVector128((Single*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + Single[] inArray1 = new Single[Op1ElementCount]; + Single[] inArray2 = new Single[Op2ElementCount]; + Single[] outArray = new Single[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, 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(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Single[] left, Single[] right, Single[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (BitConverter.SingleToInt32Bits(Helpers.FPRSqrtStepFused(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ReciprocalSquareRootStep)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ReciprocalSquareRootStep.Vector64.Single.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ReciprocalSquareRootStep.Vector64.Single.cs new file mode 100644 index 00000000000000..5bd024e902ac2b --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ReciprocalSquareRootStep.Vector64.Single.cs @@ -0,0 +1,530 @@ +// 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.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ReciprocalSquareRootStep_Vector64_Single() + { + var test = new SimpleBinaryOpTest__ReciprocalSquareRootStep_Vector64_Single(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + 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__ReciprocalSquareRootStep_Vector64_Single + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Single[] inArray1, Single[] inArray2, Single[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSingle(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSingle(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ReciprocalSquareRootStep_Vector64_Single testClass) + { + var result = AdvSimd.ReciprocalSquareRootStep(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ReciprocalSquareRootStep_Vector64_Single testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.ReciprocalSquareRootStep( + AdvSimd.LoadVector64((Single*)(pFld1)), + AdvSimd.LoadVector64((Single*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Single); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Single); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Single); + + private static Single[] _data1 = new Single[Op1ElementCount]; + private static Single[] _data2 = new Single[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ReciprocalSquareRootStep_Vector64_Single() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSingle(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSingle(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ReciprocalSquareRootStep_Vector64_Single() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSingle(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSingle(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSingle(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSingle(); } + _dataTable = new DataTable(_data1, _data2, new Single[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ReciprocalSquareRootStep( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ReciprocalSquareRootStep( + AdvSimd.LoadVector64((Single*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Single*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ReciprocalSquareRootStep), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ReciprocalSquareRootStep), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Single*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Single*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ReciprocalSquareRootStep( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ReciprocalSquareRootStep( + AdvSimd.LoadVector64((Single*)(pClsVar1)), + AdvSimd.LoadVector64((Single*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ReciprocalSquareRootStep(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Single*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Single*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ReciprocalSquareRootStep(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ReciprocalSquareRootStep_Vector64_Single(); + var result = AdvSimd.ReciprocalSquareRootStep(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ReciprocalSquareRootStep_Vector64_Single(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.ReciprocalSquareRootStep( + AdvSimd.LoadVector64((Single*)(pFld1)), + AdvSimd.LoadVector64((Single*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ReciprocalSquareRootStep(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.ReciprocalSquareRootStep( + AdvSimd.LoadVector64((Single*)(pFld1)), + AdvSimd.LoadVector64((Single*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ReciprocalSquareRootStep(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ReciprocalSquareRootStep( + AdvSimd.LoadVector64((Single*)(&test._fld1)), + AdvSimd.LoadVector64((Single*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + Single[] inArray1 = new Single[Op1ElementCount]; + Single[] inArray2 = new Single[Op2ElementCount]; + Single[] outArray = new Single[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, 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(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Single[] left, Single[] right, Single[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (BitConverter.SingleToInt32Bits(Helpers.FPRSqrtStepFused(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ReciprocalSquareRootStep)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ReciprocalStep.Vector128.Single.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ReciprocalStep.Vector128.Single.cs new file mode 100644 index 00000000000000..2b1ee402d13e77 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ReciprocalStep.Vector128.Single.cs @@ -0,0 +1,530 @@ +// 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.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ReciprocalStep_Vector128_Single() + { + var test = new SimpleBinaryOpTest__ReciprocalStep_Vector128_Single(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + 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__ReciprocalStep_Vector128_Single + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Single[] inArray1, Single[] inArray2, Single[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSingle(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSingle(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ReciprocalStep_Vector128_Single testClass) + { + var result = AdvSimd.ReciprocalStep(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ReciprocalStep_Vector128_Single testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ReciprocalStep( + AdvSimd.LoadVector128((Single*)(pFld1)), + AdvSimd.LoadVector128((Single*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Single); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Single); + private static readonly int RetElementCount = Unsafe.SizeOf>() / 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 DataTable _dataTable; + + static SimpleBinaryOpTest__ReciprocalStep_Vector128_Single() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSingle(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSingle(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ReciprocalStep_Vector128_Single() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSingle(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSingle(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSingle(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSingle(); } + _dataTable = new DataTable(_data1, _data2, new Single[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ReciprocalStep( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ReciprocalStep( + AdvSimd.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ReciprocalStep), 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() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ReciprocalStep), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ReciprocalStep( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ReciprocalStep( + AdvSimd.LoadVector128((Single*)(pClsVar1)), + AdvSimd.LoadVector128((Single*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ReciprocalStep(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Single*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Single*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ReciprocalStep(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ReciprocalStep_Vector128_Single(); + var result = AdvSimd.ReciprocalStep(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ReciprocalStep_Vector128_Single(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.ReciprocalStep( + AdvSimd.LoadVector128((Single*)(pFld1)), + AdvSimd.LoadVector128((Single*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ReciprocalStep(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ReciprocalStep( + AdvSimd.LoadVector128((Single*)(pFld1)), + AdvSimd.LoadVector128((Single*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ReciprocalStep(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ReciprocalStep( + AdvSimd.LoadVector128((Single*)(&test._fld1)), + AdvSimd.LoadVector128((Single*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + Single[] inArray1 = new Single[Op1ElementCount]; + Single[] inArray2 = new Single[Op2ElementCount]; + Single[] outArray = new Single[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, 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(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Single[] left, Single[] right, Single[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (BitConverter.SingleToInt32Bits(Helpers.FPRecipStepFused(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ReciprocalStep)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ReciprocalStep.Vector64.Single.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ReciprocalStep.Vector64.Single.cs new file mode 100644 index 00000000000000..b45351d913d35d --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ReciprocalStep.Vector64.Single.cs @@ -0,0 +1,530 @@ +// 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.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ReciprocalStep_Vector64_Single() + { + var test = new SimpleBinaryOpTest__ReciprocalStep_Vector64_Single(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + 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__ReciprocalStep_Vector64_Single + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Single[] inArray1, Single[] inArray2, Single[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSingle(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSingle(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ReciprocalStep_Vector64_Single testClass) + { + var result = AdvSimd.ReciprocalStep(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ReciprocalStep_Vector64_Single testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.ReciprocalStep( + AdvSimd.LoadVector64((Single*)(pFld1)), + AdvSimd.LoadVector64((Single*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Single); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Single); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Single); + + private static Single[] _data1 = new Single[Op1ElementCount]; + private static Single[] _data2 = new Single[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ReciprocalStep_Vector64_Single() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSingle(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSingle(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ReciprocalStep_Vector64_Single() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSingle(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSingle(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSingle(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSingle(); } + _dataTable = new DataTable(_data1, _data2, new Single[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ReciprocalStep( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ReciprocalStep( + AdvSimd.LoadVector64((Single*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Single*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ReciprocalStep), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ReciprocalStep), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Single*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Single*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ReciprocalStep( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ReciprocalStep( + AdvSimd.LoadVector64((Single*)(pClsVar1)), + AdvSimd.LoadVector64((Single*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ReciprocalStep(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Single*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Single*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ReciprocalStep(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ReciprocalStep_Vector64_Single(); + var result = AdvSimd.ReciprocalStep(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ReciprocalStep_Vector64_Single(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.ReciprocalStep( + AdvSimd.LoadVector64((Single*)(pFld1)), + AdvSimd.LoadVector64((Single*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ReciprocalStep(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.ReciprocalStep( + AdvSimd.LoadVector64((Single*)(pFld1)), + AdvSimd.LoadVector64((Single*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ReciprocalStep(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ReciprocalStep( + AdvSimd.LoadVector64((Single*)(&test._fld1)), + AdvSimd.LoadVector64((Single*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + Single[] inArray1 = new Single[Op1ElementCount]; + Single[] inArray2 = new Single[Op2ElementCount]; + Single[] outArray = new Single[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, 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(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Single[] left, Single[] right, Single[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (BitConverter.SingleToInt32Bits(Helpers.FPRecipStepFused(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ReciprocalStep)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/Shared/GenerateTests.csx b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/Shared/GenerateTests.csx index 632dc3e2ad8429..724122c2124d57 100644 --- a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/Shared/GenerateTests.csx +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/Shared/GenerateTests.csx @@ -119,6 +119,18 @@ private static readonly (string templateFileName, Dictionary tem ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AbsoluteDifference_Vector128_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteDifference", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.AbsoluteDifference(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AbsoluteDifference_Vector128_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteDifference", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.AbsoluteDifference(left[i], right[i]) != result[i]"}), ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AbsoluteDifference_Vector128_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteDifference", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.AbsoluteDifference(left[i], right[i]) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "AbsoluteDifferenceAdd_Vector64_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteDifferenceAdd", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Byte", ["Op3VectorType"] = "Vector64", ["Op3BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["NextValueOp3"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.AbsoluteDifferenceAdd(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "AbsoluteDifferenceAdd_Vector64_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteDifferenceAdd", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int16", ["Op3VectorType"] = "Vector64", ["Op3BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.AbsoluteDifferenceAdd(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "AbsoluteDifferenceAdd_Vector64_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteDifferenceAdd", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int32", ["Op3VectorType"] = "Vector64", ["Op3BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.AbsoluteDifferenceAdd(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "AbsoluteDifferenceAdd_Vector64_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteDifferenceAdd", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "SByte", ["Op3VectorType"] = "Vector64", ["Op3BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp3"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.AbsoluteDifferenceAdd(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "AbsoluteDifferenceAdd_Vector64_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteDifferenceAdd", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt16", ["Op3VectorType"] = "Vector64", ["Op3BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.AbsoluteDifferenceAdd(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "AbsoluteDifferenceAdd_Vector64_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteDifferenceAdd", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt32", ["Op3VectorType"] = "Vector64", ["Op3BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.AbsoluteDifferenceAdd(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "AbsoluteDifferenceAdd_Vector128_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteDifferenceAdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Byte", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["NextValueOp3"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.AbsoluteDifferenceAdd(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "AbsoluteDifferenceAdd_Vector128_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteDifferenceAdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.AbsoluteDifferenceAdd(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "AbsoluteDifferenceAdd_Vector128_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteDifferenceAdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int32", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.AbsoluteDifferenceAdd(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "AbsoluteDifferenceAdd_Vector128_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteDifferenceAdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "SByte", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp3"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.AbsoluteDifferenceAdd(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "AbsoluteDifferenceAdd_Vector128_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteDifferenceAdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt16", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.AbsoluteDifferenceAdd(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "AbsoluteDifferenceAdd_Vector128_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteDifferenceAdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt32", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.AbsoluteDifferenceAdd(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Add_Vector64_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Add", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.Add(left[i], right[i]) != result[i]"}), ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Add_Vector64_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Add", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.Add(left[i], right[i]) != result[i]"}), ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Add_Vector64_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Add", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.Add(left[i], right[i]) != result[i]"}), @@ -502,10 +514,26 @@ private static readonly (string templateFileName, Dictionary tem ("VecBinOpTest.template", new Dictionary { ["TestName"] = "OrNot_Vector128_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "OrNot", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.OrNot(left[i], right[i]) != result[i]"}), ("VecBinOpTest.template", new Dictionary { ["TestName"] = "OrNot_Vector128_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "OrNot", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.OrNot(left[i], right[i]) != result[i]"}), ("VecBinOpTest.template", new Dictionary { ["TestName"] = "OrNot_Vector128_UInt64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "OrNot", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["ValidateIterResult"] = "Helpers.OrNot(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "PolynomialMultiply_Vector64_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "PolynomialMultiply", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.PolynomialMultiply(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "PolynomialMultiply_Vector64_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "PolynomialMultiply", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.PolynomialMultiply(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "PolynomialMultiply_Vector128_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "PolynomialMultiply", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.PolynomialMultiply(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "PolynomialMultiply_Vector128_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "PolynomialMultiply", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.PolynomialMultiply(left[i], right[i]) != result[i]"}), ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "PopCount_Vector64_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "PopCount", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.BitCount(firstOp[i]) != result[i]"}), ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "PopCount_Vector64_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "PopCount", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.BitCount(firstOp[i]) != result[i]"}), ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "PopCount_Vector128_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "PopCount", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.BitCount(firstOp[i]) != result[i]"}), ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "PopCount_Vector128_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "PopCount", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.BitCount(firstOp[i]) != result[i]"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "ReciprocalEstimate_Vector64_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ReciprocalEstimate", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "BitConverter.Int32BitsToSingle(0x3e4ed9ed)", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(result[i]) != 0x409e8000"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "ReciprocalEstimate_Vector64_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ReciprocalEstimate", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.UnsignedRecipEstimate(firstOp[i]) != result[i]"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "ReciprocalEstimate_Vector128_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ReciprocalEstimate", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "BitConverter.Int32BitsToSingle(0x3e4ed9ed)", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(result[i]) != 0x409e8000"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "ReciprocalEstimate_Vector128_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ReciprocalEstimate", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.UnsignedRecipEstimate(firstOp[i]) != result[i]"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "ReciprocalSquareRootEstimate_Vector64_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ReciprocalSquareRootEstimate", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "BitConverter.Int32BitsToSingle(0x3e4ed9ed)", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(result[i]) != 0x400e8000"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "ReciprocalSquareRootEstimate_Vector64_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ReciprocalSquareRootEstimate", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.UnsignedRSqrtEstimate(firstOp[i]) != result[i]"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "ReciprocalSquareRootEstimate_Vector128_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ReciprocalSquareRootEstimate", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "BitConverter.Int32BitsToSingle(0x3e4ed9ed)", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(result[i]) != 0x400e8000"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "ReciprocalSquareRootEstimate_Vector128_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ReciprocalSquareRootEstimate", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.UnsignedRSqrtEstimate(firstOp[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "ReciprocalSquareRootStep_Vector64_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ReciprocalSquareRootStep", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.FPRSqrtStepFused(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "ReciprocalSquareRootStep_Vector128_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ReciprocalSquareRootStep", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.FPRSqrtStepFused(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "ReciprocalStep_Vector64_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ReciprocalStep", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.FPRecipStepFused(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "ReciprocalStep_Vector128_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ReciprocalStep", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.FPRecipStepFused(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), ("SimpleUnOpTest.template", new Dictionary { ["TestName"] = "SqrtScalar_Vector64_Double", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "SqrtScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Double", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(Helpers.Sqrt(firstOp[0])) != BitConverter.DoubleToInt64Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.DoubleToInt64Bits(result[i]) != 0"}), ("SimpleUnOpTest.template", new Dictionary { ["TestName"] = "SqrtScalar_Vector64_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "SqrtScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["ValidateFirstResult"] = "BitConverter.SingleToInt32Bits(Helpers.Sqrt(firstOp[0])) != BitConverter.SingleToInt32Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.SingleToInt32Bits(result[i]) != 0"}), ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Subtract_Vector64_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Subtract", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.Subtract(left[i], right[i]) != result[i]"}), @@ -704,9 +732,28 @@ private static readonly (string templateFileName, Dictionary tem ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "MinScalar_Vector64_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MinScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(Helpers.Min(left[0], right[0])) != BitConverter.DoubleToInt64Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.DoubleToInt64Bits(result[i]) != 0"}), ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "MinScalar_Vector64_Single", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MinScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateFirstResult"] = "BitConverter.SingleToInt32Bits(Helpers.Min(left[0], right[0])) != BitConverter.SingleToInt32Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.SingleToInt32Bits(result[i]) != 0"}), ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Multiply_Vector128_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "Multiply", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(Helpers.Multiply(left[i], right[i])) != BitConverter.DoubleToInt64Bits(result[i])"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "MultiplyExtended_Vector64_Single", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MultiplyExtended", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.MultiplyExtended(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "MultiplyExtended_Vector128_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MultiplyExtended", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(Helpers.MultiplyExtended(left[i], right[i])) != BitConverter.DoubleToInt64Bits(result[i])"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "MultiplyExtended_Vector128_Single", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MultiplyExtended", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.MultiplyExtended(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "MultiplyExtendedScalar_Vector64_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MultiplyExtendedScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(Helpers.MultiplyExtended(left[0], right[0])) != BitConverter.DoubleToInt64Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.DoubleToInt64Bits(result[i]) != 0"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "MultiplyExtendedScalar_Vector64_Single", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MultiplyExtendedScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateFirstResult"] = "BitConverter.SingleToInt32Bits(Helpers.MultiplyExtended(left[0], right[0])) != BitConverter.SingleToInt32Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.SingleToInt32Bits(result[i]) != 0"}), ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "Negate_Vector128_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "Negate", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(Helpers.Negate(firstOp[i])) != BitConverter.DoubleToInt64Bits(result[i])"}), ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "Negate_Vector128_Int64", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "Negate", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["ValidateIterResult"] = "Helpers.Negate(firstOp[i]) != result[i]"}), ("SimpleUnOpTest.template", new Dictionary { ["TestName"] = "NegateScalar_Vector64_Int64", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "NegateScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["ValidateFirstResult"] = "Helpers.Negate(firstOp[0]) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "ReciprocalEstimate_Vector128_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ReciprocalEstimate", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "BitConverter.Int64BitsToDouble(0x3fc9db3dab555868)", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(result[i]) != 0x4013d00000000000"}), + ("SimpleUnOpTest.template", new Dictionary { ["TestName"] = "ReciprocalEstimateScalar_Vector64_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ReciprocalEstimateScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Double", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "BitConverter.Int64BitsToDouble(0x3fc9db3dab555868)", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(result[0]) != 0x4013d00000000000", ["ValidateRemainingResults"] = "BitConverter.DoubleToInt64Bits(result[i]) != 0"}), + ("SimpleUnOpTest.template", new Dictionary { ["TestName"] = "ReciprocalEstimateScalar_Vector64_Single", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ReciprocalEstimateScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "BitConverter.Int32BitsToSingle(0x3e4ed9ed)", ["ValidateFirstResult"] = "BitConverter.SingleToInt32Bits(result[0]) != 0x409e8000", ["ValidateRemainingResults"] = "BitConverter.SingleToInt32Bits(result[i]) != 0"}), + ("SimpleUnOpTest.template", new Dictionary { ["TestName"] = "ReciprocalExponentScalar_Vector64_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ReciprocalExponentScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Double", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "BitConverter.Int64BitsToDouble(0x3fc9db3dab555868)", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(result[0]) != 0x4030000000000000", ["ValidateRemainingResults"] = "BitConverter.DoubleToInt64Bits(result[i]) != 0"}), + ("SimpleUnOpTest.template", new Dictionary { ["TestName"] = "ReciprocalExponentScalar_Vector64_Single", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ReciprocalExponentScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "BitConverter.Int32BitsToSingle(0x3e4ed9ed)", ["ValidateFirstResult"] = "BitConverter.SingleToInt32Bits(result[0]) != 0x41800000", ["ValidateRemainingResults"] = "BitConverter.SingleToInt32Bits(result[i]) != 0"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "ReciprocalSquareRootEstimate_Vector128_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ReciprocalSquareRootEstimate", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "BitConverter.Int64BitsToDouble(0x3fc9db3dab555868)", ["ValidateIterResult"] = " BitConverter.DoubleToInt64Bits(result[i]) != 0x4001d00000000000"}), + ("SimpleUnOpTest.template", new Dictionary { ["TestName"] = "ReciprocalSquareRootEstimateScalar_Vector64_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ReciprocalSquareRootEstimateScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Double", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "BitConverter.Int64BitsToDouble(0x3fc9db3dab555868)", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(result[0]) != 0x4001d00000000000", ["ValidateRemainingResults"] = "BitConverter.DoubleToInt64Bits(result[i]) != 0"}), + ("SimpleUnOpTest.template", new Dictionary { ["TestName"] = "ReciprocalSquareRootEstimateScalar_Vector64_Single", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ReciprocalSquareRootEstimateScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "BitConverter.Int32BitsToSingle(0x3e4ed9ed)", ["ValidateFirstResult"] = "BitConverter.SingleToInt32Bits(result[0]) != 0x400e8000", ["ValidateRemainingResults"] = "BitConverter.SingleToInt32Bits(result[i]) != 0"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "ReciprocalSquareRootStep_Vector128_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ReciprocalSquareRootStep", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(Helpers.FPRSqrtStepFused(left[i], right[i])) != BitConverter.DoubleToInt64Bits(result[i])"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "ReciprocalSquareRootStepScalar_Vector64_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ReciprocalSquareRootStepScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(Helpers.FPRSqrtStepFused(left[0], right[0])) != BitConverter.DoubleToInt64Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.DoubleToInt64Bits(result[i]) != 0"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "ReciprocalSquareRootStepScalar_Vector64_Single", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ReciprocalSquareRootStepScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateFirstResult"] = "BitConverter.SingleToInt32Bits(Helpers.FPRSqrtStepFused(left[0], right[0])) != BitConverter.SingleToInt32Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.SingleToInt32Bits(result[i]) != 0"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "ReciprocalStep_Vector128_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ReciprocalStep", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(Helpers.FPRecipStepFused(left[i], right[i])) != BitConverter.DoubleToInt64Bits(result[i])"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "ReciprocalStepScalar_Vector64_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ReciprocalStepScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(Helpers.FPRecipStepFused(left[0], right[0])) != BitConverter.DoubleToInt64Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.DoubleToInt64Bits(result[i]) != 0"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "ReciprocalStepScalar_Vector64_Single", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ReciprocalStepScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateFirstResult"] = "BitConverter.SingleToInt32Bits(Helpers.FPRecipStepFused(left[0], right[0])) != BitConverter.SingleToInt32Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.SingleToInt32Bits(result[i]) != 0"}), ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "ReverseElementBits_Vector128_Byte", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ReverseElementBits", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.ReverseElementBits(firstOp[i]) != result[i]"}), ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "ReverseElementBits_Vector128_SByte", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ReverseElementBits", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.ReverseElementBits(firstOp[i]) != result[i]"}), ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "ReverseElementBits_Vector64_Byte", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ReverseElementBits", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.ReverseElementBits(firstOp[i]) != result[i]"}), @@ -896,7 +943,7 @@ private static void ProcessInputs(string groupName, (string templateFileName, Di True "); - + testListFile.WriteLine(@"// 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. diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/Shared/Helpers.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/Shared/Helpers.cs index 7e7e8d7c4ad595..8c227f85b086ad 100644 --- a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/Shared/Helpers.cs +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/Shared/Helpers.cs @@ -1409,17 +1409,29 @@ public static float CompareTest(float left, float right) public static double Sqrt(double value) => Math.Sqrt(value); - public static byte AbsoluteDifference(sbyte left, sbyte right) => (byte)Math.Abs((long)left - (long)right); + public static byte AbsoluteDifference(sbyte op1, sbyte op2) => op1 < op2 ? (byte)(op2 - op1) : (byte)(op1 - op2); - public static ushort AbsoluteDifference(short left, short right) => (ushort)Math.Abs((long)left - (long)right); + public static sbyte AbsoluteDifferenceAdd(sbyte op1, sbyte op2, sbyte op3) => (sbyte)(op1 + AbsoluteDifference(op2, op3)); - public static uint AbsoluteDifference(int left, int right) => (uint)Math.Abs((long)left - (long)right); + public static ushort AbsoluteDifference(short op1, short op2) => op1 < op2 ? (ushort)(op2 - op1) : (ushort)(op1 - op2); - public static byte AbsoluteDifference(byte left, byte right) => (byte)Math.Abs((long)left - (long)right); + public static short AbsoluteDifferenceAdd(short op1, short op2, short op3) => (short)(op1 + AbsoluteDifference(op2, op3)); - public static ushort AbsoluteDifference(ushort left, ushort right) => (ushort)Math.Abs((long)left - (long)right); + public static uint AbsoluteDifference(int op1, int op2) => op1 < op2 ? (uint)(op2 - op1) : (uint)(op1 - op2); - public static uint AbsoluteDifference(uint left, uint right) => (uint)Math.Abs((long)left - (long)right); + public static int AbsoluteDifferenceAdd(int op1, int op2, int op3) => (int)(op1 + AbsoluteDifference(op2, op3)); + + public static byte AbsoluteDifference(byte op1, byte op2) => op1 < op2 ? (byte)(op2 - op1) : (byte)(op1 - op2); + + public static byte AbsoluteDifferenceAdd(byte op1, byte op2, byte op3) => (byte)(op1 + AbsoluteDifference(op2, op3)); + + public static ushort AbsoluteDifference(ushort op1, ushort op2) => op1 < op2 ? (ushort)(op2 - op1) : (ushort)(op1 - op2); + + public static ushort AbsoluteDifferenceAdd(ushort op1, ushort op2, ushort op3) => (ushort)(op1 + AbsoluteDifference(op2, op3)); + + public static uint AbsoluteDifference(uint op1, uint op2) => op1 < op2 ? (uint)(op2 - op1) : (uint)(op1 - op2); + + public static uint AbsoluteDifferenceAdd(uint op1, uint op2, uint op3) => (uint)(op1 + AbsoluteDifference(op2, op3)); public static float AbsoluteDifference(float op1, float op2) => MathF.Abs(op1 - op2); @@ -1443,6 +1455,28 @@ public static float CompareTest(float left, float right) public static float MinNumberPairwise(float[] op1, float[] op2, int i) => Pairwise(MinNumber, op1, op2, i); + public static float MultiplyExtended(float op1, float op2) + { + bool inf1 = float.IsInfinity(op1); + bool inf2 = float.IsInfinity(op2); + + bool zero1 = (op1 == 0); + bool zero2 = (op2 == 0); + + if ((inf1 && zero2) || (zero1 && inf2)) + { + return MathF.CopySign(2, (zero1 ? op2 : op1)); + } + else + { + return op1 * op2; + } + } + + public static float FPRecipStepFused(float op1, float op2) => FusedMultiplySubtract(2, op1, op2); + + public static float FPRSqrtStepFused(float op1, float op2) => FusedMultiplySubtract(3, op1, op2) / 2; + public static double AbsoluteDifference(double op1, double op2) => Math.Abs(op1 - op2); public static double FusedMultiplyAdd(double op1, double op2, double op3) => Math.FusedMultiplyAdd(op2, op3, op1); @@ -1465,6 +1499,108 @@ public static float CompareTest(float left, float right) public static double MinNumberPairwise(double[] op1, double[] op2, int i) => Pairwise(MinNumber, op1, op2, i); + public static double MultiplyExtended(double op1, double op2) + { + bool inf1 = double.IsInfinity(op1); + bool inf2 = double.IsInfinity(op2); + + bool zero1 = (op1 == 0); + bool zero2 = (op2 == 0); + + if ((inf1 && zero2) || (zero1 && inf2)) + { + return Math.CopySign(2, (zero1 ? op2 : op1)); + } + else + { + return op1 * op2; + } + } + + public static double FPRecipStepFused(double op1, double op2) => FusedMultiplySubtract(2, op1, op2); + + public static double FPRSqrtStepFused(double op1, double op2) => FusedMultiplySubtract(3, op1, op2) / 2; + + private static uint RecipEstimate(uint a) + { + a = a * 2 + 1; + + uint b = (1 << 19) / a; + uint r = (b + 1) / 2; + + return r; + } + + private static uint RecipSqrtEstimate(uint a) + { + if (a < 256) + { + a = a * 2 + 1; + } + else + { + a = (a >> 1) << 1; + a = (a + 1) * 2; + } + + uint b = 512; + + while (a * (b + 1) * (b + 1) < (1 << 28)) + { + b = b + 1; + } + + uint r = (b + 1) / 2; + + return r; + } + + private static uint ExtractBits(uint val, byte msbPos, byte lsbPos) + { + uint andMask = 0; + + for (byte pos = lsbPos; pos <= msbPos; pos++) + { + andMask |= (uint)1 << pos; + } + + return (val & andMask) >> lsbPos; + } + + public static uint UnsignedRecipEstimate(uint op1) + { + uint result; + + if ((op1 & (1 << 31)) == 0) + { + result = ~0U; + } + else + { + uint estimate = RecipEstimate(ExtractBits(op1, 31, 23)); + result = ExtractBits(estimate, 8, 0) << 31; + } + + return result; + } + + public static uint UnsignedRSqrtEstimate(uint op1) + { + uint result; + + if ((op1 & (3 << 30)) == 0) + { + result = ~0U; + } + else + { + uint estimate = RecipSqrtEstimate(ExtractBits(op1, 31, 23)); + result = ExtractBits(estimate, 8, 0) << 31; + } + + return result; + } + public static sbyte Add(sbyte op1, sbyte op2) => (sbyte)(op1 + op2); public static sbyte AddPairwise(sbyte[] op1, int i) => Pairwise(Add, op1, i); @@ -2124,5 +2260,42 @@ private static double Reduce(Func reduceOp, double[] op1 public static float MaxNumberAcross(float[] op1) => Reduce(MaxNumber, op1); public static float MinNumberAcross(float[] op1) => Reduce(MinNumber, op1); + + private static ulong PolynomialMult(sbyte op1, sbyte op2) + { + ulong result = 0; + ulong extendedOp2 = (ulong)op2; + + for (int i = 0; i < 8 * sizeof(sbyte); i++) + { + if ((op1 & (1 << i)) != 0) + { + result ^= (extendedOp2 << i); + } + } + + return result; + } + + public static sbyte PolynomialMultiply(sbyte op1, sbyte op2) => (sbyte)PolynomialMult(op1, op2); + + private static ulong PolynomialMult(byte op1, byte op2) + { + ulong result = 0; + ulong extendedOp2 = (ulong)op2; + + for (int i = 0; i < 8 * sizeof(byte); i++) + { + if ((op1 & (1 << i)) != 0) + { + result ^= (extendedOp2 << i); + } + } + + return result; + } + + public static byte PolynomialMultiply(byte op1, byte op2) => (byte)PolynomialMult(op1, op2); + } } diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/Shared/Helpers.tt b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/Shared/Helpers.tt index 9903796421ba9a..bfce0ea3dd3259 100644 --- a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/Shared/Helpers.tt +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/Shared/Helpers.tt @@ -316,7 +316,9 @@ namespace JIT.HardwareIntrinsics.Arm (name: "uint", unsigned: "uint") }) { #> - public static <#= type.unsigned #> AbsoluteDifference(<#= type.name #> left, <#= type.name #> right) => (<#= type.unsigned #>)Math.Abs((long)left - (long)right); + public static <#= type.unsigned #> AbsoluteDifference(<#= type.name #> op1, <#= type.name #> op2) => op1 < op2 ? (<#= type.unsigned #>)(op2 - op1) : (<#= type.unsigned #>)(op1 - op2); + + public static <#= type.name #> AbsoluteDifferenceAdd(<#= type.name #> op1, <#= type.name #> op2, <#= type.name #> op3) => (<#= type.name #>)(op1 + AbsoluteDifference(op2, op3)); <# } @@ -346,9 +348,119 @@ namespace JIT.HardwareIntrinsics.Arm public static <#= typeName #> MinNumberPairwise(<#= typeName #>[] op1, <#= typeName #>[] op2, int i) => Pairwise(MinNumber, op1, op2, i); + public static <#= typeName #> MultiplyExtended(<#= typeName #> op1, <#= typeName #> op2) + { + bool inf1 = <#= typeName #>.IsInfinity(op1); + bool inf2 = <#= typeName #>.IsInfinity(op2); + + bool zero1 = (op1 == 0); + bool zero2 = (op2 == 0); + + if ((inf1 && zero2) || (zero1 && inf2)) + { + return <#= className #>.CopySign(2, (zero1 ? op2 : op1)); + } + else + { + return op1 * op2; + } + } + + public static <#= typeName #> FPRecipStepFused(<#= typeName #> op1, <#= typeName #> op2) => FusedMultiplySubtract(2, op1, op2); + + public static <#= typeName #> FPRSqrtStepFused(<#= typeName #> op1, <#= typeName #> op2) => FusedMultiplySubtract(3, op1, op2) / 2; + <# } +#> + private static uint RecipEstimate(uint a) + { + a = a * 2 + 1; + + uint b = (1 << 19) / a; + uint r = (b + 1) / 2; + return r; + } + + private static uint RecipSqrtEstimate(uint a) + { + if (a < 256) + { + a = a * 2 + 1; + } + else + { + a = (a >> 1) << 1; + a = (a + 1) * 2; + } + + uint b = 512; + + while (a * (b + 1) * (b + 1) < (1 << 28)) + { + b = b + 1; + } + + uint r = (b + 1) / 2; + + return r; + } + +<# + foreach (string typeName in new string[] { "uint" }) + { +#> + private static <#= typeName #> ExtractBits(<#= typeName #> val, byte msbPos, byte lsbPos) + { + <#= typeName #> andMask = 0; + + for (byte pos = lsbPos; pos <= msbPos; pos++) + { + andMask |= (<#= typeName #>)1 << pos; + } + + return (val & andMask) >> lsbPos; + } + +<# + } +#> + public static uint UnsignedRecipEstimate(uint op1) + { + uint result; + + if ((op1 & (1 << 31)) == 0) + { + result = ~0U; + } + else + { + uint estimate = RecipEstimate(ExtractBits(op1, 31, 23)); + result = ExtractBits(estimate, 8, 0) << 31; + } + + return result; + } + + public static uint UnsignedRSqrtEstimate(uint op1) + { + uint result; + + if ((op1 & (3 << 30)) == 0) + { + result = ~0U; + } + else + { + uint estimate = RecipSqrtEstimate(ExtractBits(op1, 31, 23)); + result = ExtractBits(estimate, 8, 0) << 31; + } + + return result; + } + +<# foreach (string typeName in new string[] { "sbyte", "byte", "short", "ushort", "int", "uint", "long", "ulong", "float", "double" }) { #> @@ -440,5 +552,31 @@ namespace JIT.HardwareIntrinsics.Arm public static float MaxNumberAcross(float[] op1) => Reduce(MaxNumber, op1); public static float MinNumberAcross(float[] op1) => Reduce(MinNumber, op1); + +<# + foreach (string typeName in new string[] { "sbyte", "byte" }) + { +#> + private static ulong PolynomialMult(<#= typeName #> op1, <#= typeName #> op2) + { + ulong result = 0; + ulong extendedOp2 = (ulong)op2; + + for (int i = 0; i < 8 * sizeof(<#= typeName #>); i++) + { + if ((op1 & (1 << i)) != 0) + { + result ^= (extendedOp2 << i); + } + } + + return result; + } + + public static <#= typeName #> PolynomialMultiply(<#= typeName #> op1, <#= typeName #> op2) => (<#= typeName #>)PolynomialMult(op1, op2); + +<# + } +#> } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/AdvSimd.PlatformNotSupported.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/AdvSimd.PlatformNotSupported.cs index a51ae8b59dfd40..26b31d07bdf1e3 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/AdvSimd.PlatformNotSupported.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/AdvSimd.PlatformNotSupported.cs @@ -984,6 +984,36 @@ internal Arm64() { } /// public static Vector128 Multiply(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + /// + /// float32x2_t vmulx_f32 (float32x2_t a, float32x2_t b) + /// A64: FMULX Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 MultiplyExtended(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// float64x2_t vmulxq_f64 (float64x2_t a, float64x2_t b) + /// A64: FMULX Vd.2D, Vn.2D, Vm.2D + /// + public static Vector128 MultiplyExtended(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// float32x4_t vmulxq_f32 (float32x4_t a, float32x4_t b) + /// A64: FMULX Vd.4S, Vn.4S, Vm.4S + /// + public static Vector128 MultiplyExtended(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// float64x1_t vmulx_f64 (float64x1_t a, float64x1_t b) + /// A64: FMULX Dd, Dn, Dm + /// + public static Vector64 MultiplyExtendedScalar(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// float32_t vmulxs_f32 (float32_t a, float32_t b) + /// A64: FMULX Sd, Sn, Sm + /// + public static Vector64 MultiplyExtendedScalar(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + /// /// float64x2_t vnegq_f64 (float64x2_t a) /// A64: FNEG Vd.2D, Vn.2D @@ -1002,6 +1032,90 @@ internal Arm64() { } /// public static Vector64 NegateScalar(Vector64 value) { throw new PlatformNotSupportedException(); } + /// + /// float64x2_t vrecpeq_f64 (float64x2_t a) + /// A64: FRECPE Vd.2D, Vn.2D + /// + public static Vector128 ReciprocalEstimate(Vector128 value) { throw new PlatformNotSupportedException(); } + + /// + /// float64x1_t vrecpe_f64 (float64x1_t a) + /// A64: FRECPE Dd, Dn + /// + public static Vector64 ReciprocalEstimateScalar(Vector64 value) { throw new PlatformNotSupportedException(); } + + /// + /// float32_t vrecpes_f32 (float32_t a) + /// A64: FRECPE Sd, Sn + /// + public static Vector64 ReciprocalEstimateScalar(Vector64 value) { throw new PlatformNotSupportedException(); } + + /// + /// float64_t vrecpxd_f64 (float64_t a) + /// A64: FRECPX Dd, Dn + /// + public static Vector64 ReciprocalExponentScalar(Vector64 value) { throw new PlatformNotSupportedException(); } + + /// + /// float32_t vrecpxs_f32 (float32_t a) + /// A64: FRECPX Sd, Sn + /// + public static Vector64 ReciprocalExponentScalar(Vector64 value) { throw new PlatformNotSupportedException(); } + + /// + /// float64x2_t vrsqrteq_f64 (float64x2_t a) + /// A64: FRSQRTE Vd.2D, Vn.2D + /// + public static Vector128 ReciprocalSquareRootEstimate(Vector128 value) { throw new PlatformNotSupportedException(); } + + /// + /// float64x1_t vrsqrte_f64 (float64x1_t a) + /// A64: FRSQRTE Dd, Dn + /// + public static Vector64 ReciprocalSquareRootEstimateScalar(Vector64 value) { throw new PlatformNotSupportedException(); } + + /// + /// float32_t vrsqrtes_f32 (float32_t a) + /// A64: FRSQRTE Sd, Sn + /// + public static Vector64 ReciprocalSquareRootEstimateScalar(Vector64 value) { throw new PlatformNotSupportedException(); } + + /// + /// float64x2_t vrsqrtsq_f64 (float64x2_t a, float64x2_t b) + /// A64: FRSQRTS Vd.2D, Vn.2D, Vm.2D + /// + public static Vector128 ReciprocalSquareRootStep(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// float64x1_t vrsqrts_f64 (float64x1_t a, float64x1_t b) + /// A64: FRSQRTS Dd, Dn, Dm + /// + public static Vector64 ReciprocalSquareRootStepScalar(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// float32_t vrsqrtss_f32 (float32_t a, float32_t b) + /// A64: FRSQRTS Sd, Sn, Sm + /// + public static Vector64 ReciprocalSquareRootStepScalar(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// float64x2_t vrecpsq_f64 (float64x2_t a, float64x2_t b) + /// A64: FRECPS Vd.2D, Vn.2D, Vm.2D + /// + public static Vector128 ReciprocalStep(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// float64x1_t vrecps_f64 (float64x1_t a, float64x1_t b) + /// A64: FRECPS Dd, Dn, Dm + /// + public static Vector64 ReciprocalStepScalar(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// float32_t vrecpss_f32 (float32_t a, float32_t b) + /// A64: FRECPS Sd, Sn, Sm + /// + public static Vector64 ReciprocalStepScalar(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + /// /// float32x2_t vsqrt_f32 (float32x2_t a) /// A64: FSQRT Vd.2S, Vn.2S @@ -1900,6 +2014,90 @@ internal Arm64() { } /// public static Vector128 AbsoluteDifference(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + /// + /// uint8x8_t vaba_u8 (uint8x8_t a, uint8x8_t b, uint8x8_t c) + /// A32: VABA.U8 Dd, Dn, Dm + /// A64: UABA Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 AbsoluteDifferenceAdd(Vector64 addend, Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// int16x4_t vaba_s16 (int16x4_t a, int16x4_t b, int16x4_t c) + /// A32: VABA.S16 Dd, Dn, Dm + /// A64: SABA Vd.4H, Vn.4H, Vm.4H + /// + public static Vector64 AbsoluteDifferenceAdd(Vector64 addend, Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// int32x2_t vaba_s32 (int32x2_t a, int32x2_t b, int32x2_t c) + /// A32: VABA.S32 Dd, Dn, Dm + /// A64: SABA Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 AbsoluteDifferenceAdd(Vector64 addend, Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// int8x8_t vaba_s8 (int8x8_t a, int8x8_t b, int8x8_t c) + /// A32: VABA.S8 Dd, Dn, Dm + /// A64: SABA Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 AbsoluteDifferenceAdd(Vector64 addend, Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint16x4_t vaba_u16 (uint16x4_t a, uint16x4_t b, uint16x4_t c) + /// A32: VABA.U16 Dd, Dn, Dm + /// A64: UABA Vd.4H, Vn.4H, Vm.4H + /// + public static Vector64 AbsoluteDifferenceAdd(Vector64 addend, Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x2_t vaba_u32 (uint32x2_t a, uint32x2_t b, uint32x2_t c) + /// A32: VABA.U32 Dd, Dn, Dm + /// A64: UABA Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 AbsoluteDifferenceAdd(Vector64 addend, Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint8x16_t vabaq_u8 (uint8x16_t a, uint8x16_t b, uint8x16_t c) + /// A32: VABA.U8 Qd, Qn, Qm + /// A64: UABA Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 AbsoluteDifferenceAdd(Vector128 addend, Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// int16x8_t vabaq_s16 (int16x8_t a, int16x8_t b, int16x8_t c) + /// A32: VABA.S16 Qd, Qn, Qm + /// A64: SABA Vd.8H, Vn.8H, Vm.8H + /// + public static Vector128 AbsoluteDifferenceAdd(Vector128 addend, Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// int32x4_t vabaq_s32 (int32x4_t a, int32x4_t b, int32x4_t c) + /// A32: VABA.S32 Qd, Qn, Qm + /// A64: SABA Vd.4S, Vn.4S, Vm.4S + /// + public static Vector128 AbsoluteDifferenceAdd(Vector128 addend, Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// int8x16_t vabaq_s8 (int8x16_t a, int8x16_t b, int8x16_t c) + /// A32: VABA.S8 Qd, Qn, Qm + /// A64: SABA Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 AbsoluteDifferenceAdd(Vector128 addend, Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint16x8_t vabaq_u16 (uint16x8_t a, uint16x8_t b, uint16x8_t c) + /// A32: VABA.U16 Qd, Qn, Qm + /// A64: UABA Vd.8H, Vn.8H, Vm.8H + /// + public static Vector128 AbsoluteDifferenceAdd(Vector128 addend, Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x4_t vabaq_u32 (uint32x4_t a, uint32x4_t b, uint32x4_t c) + /// A32: VABA.U32 Qd, Qn, Qm + /// A64: UABA Vd.4S, Vn.4S, Vm.4S + /// + public static Vector128 AbsoluteDifferenceAdd(Vector128 addend, Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + /// /// uint8x8_t vadd_u8 (uint8x8_t a, uint8x8_t b) /// A32: VADD.I8 Dd, Dn, Dm @@ -4613,6 +4811,34 @@ internal Arm64() { } /// public static Vector128 OrNot(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + /// + /// poly8x8_t vmul_p8 (poly8x8_t a, poly8x8_t b) + /// A32: VMUL.P8 Dd, Dn, Dm + /// A64: PMUL Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 PolynomialMultiply(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// poly8x8_t vmul_p8 (poly8x8_t a, poly8x8_t b) + /// A32: VMUL.P8 Dd, Dn, Dm + /// A64: PMUL Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 PolynomialMultiply(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// poly8x16_t vmulq_p8 (poly8x16_t a, poly8x16_t b) + /// A32: VMUL.P8 Qd, Qn, Qm + /// A64: PMUL Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 PolynomialMultiply(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// poly8x16_t vmulq_p8 (poly8x16_t a, poly8x16_t b) + /// A32: VMUL.P8 Qd, Qn, Qm + /// A64: PMUL Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 PolynomialMultiply(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + /// /// uint8x8_t vcnt_u8 (uint8x8_t a) /// A32: VCNT.I8 Dd, Dm @@ -4641,6 +4867,90 @@ internal Arm64() { } /// public static Vector128 PopCount(Vector128 value) { throw new PlatformNotSupportedException(); } + /// + /// float32x2_t vrecpe_f32 (float32x2_t a) + /// A32: VRECPE.F32 Dd, Dm + /// A64: FRECPE Vd.2S, Vn.2S + /// + public static Vector64 ReciprocalEstimate(Vector64 value) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x2_t vrecpe_u32 (uint32x2_t a) + /// A32: VRECPE.U32 Dd, Dm + /// A64: URECPE Vd.2S, Vn.2S + /// + public static Vector64 ReciprocalEstimate(Vector64 value) { throw new PlatformNotSupportedException(); } + + /// + /// float32x4_t vrecpeq_f32 (float32x4_t a) + /// A32: VRECPE.F32 Qd, Qm + /// A64: FRECPE Vd.4S, Vn.4S + /// + public static Vector128 ReciprocalEstimate(Vector128 value) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x4_t vrecpeq_u32 (uint32x4_t a) + /// A32: VRECPE.U32 Qd, Qm + /// A64: URECPE Vd.4S, Vn.4S + /// + public static Vector128 ReciprocalEstimate(Vector128 value) { throw new PlatformNotSupportedException(); } + + /// + /// float32x2_t vrsqrte_f32 (float32x2_t a) + /// A32: VRSQRTE.F32 Dd, Dm + /// A64: FRSQRTE Vd.2S, Vn.2S + /// + public static Vector64 ReciprocalSquareRootEstimate(Vector64 value) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x2_t vrsqrte_u32 (uint32x2_t a) + /// A32: VRSQRTE.U32 Dd, Dm + /// A64: URSQRTE Vd.2S, Vn.2S + /// + public static Vector64 ReciprocalSquareRootEstimate(Vector64 value) { throw new PlatformNotSupportedException(); } + + /// + /// float32x4_t vrsqrteq_f32 (float32x4_t a) + /// A32: VRSQRTE.F32 Qd, Qm + /// A64: FRSQRTE Vd.4S, Vn.4S + /// + public static Vector128 ReciprocalSquareRootEstimate(Vector128 value) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x4_t vrsqrteq_u32 (uint32x4_t a) + /// A32: VRSQRTE.U32 Qd, Qm + /// A64: URSQRTE Vd.4S, Vn.4S + /// + public static Vector128 ReciprocalSquareRootEstimate(Vector128 value) { throw new PlatformNotSupportedException(); } + + /// + /// float32x2_t vrsqrts_f32 (float32x2_t a, float32x2_t b) + /// A32: VRSQRTS.F32 Dd, Dn, Dm + /// A64: FRSQRTS Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 ReciprocalSquareRootStep(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// float32x4_t vrsqrtsq_f32 (float32x4_t a, float32x4_t b) + /// A32: VRSQRTS.F32 Qd, Qn, Qm + /// A64: FRSQRTS Vd.4S, Vn.4S, Vm.4S + /// + public static Vector128 ReciprocalSquareRootStep(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// float32x2_t vrecps_f32 (float32x2_t a, float32x2_t b) + /// A32: VRECPS.F32 Dd, Dn, Dm + /// A64: FRECPS Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 ReciprocalStep(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// float32x4_t vrecpsq_f32 (float32x4_t a, float32x4_t b) + /// A32: VRECPS.F32 Qd, Qn, Qm + /// A64: FRECPS Vd.4S, Vn.4S, Vm.4S + /// + public static Vector128 ReciprocalStep(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + /// /// float64x1_t vsqrt_f64 (float64x1_t a) /// A32: VSQRT.F64 Dd, Dm diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/AdvSimd.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/AdvSimd.cs index 112dc1e566d0f2..63c0cd2866de2d 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/AdvSimd.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/AdvSimd.cs @@ -986,6 +986,36 @@ internal Arm64() { } /// public static Vector128 Multiply(Vector128 left, Vector128 right) => Multiply(left, right); + /// + /// float32x2_t vmulx_f32 (float32x2_t a, float32x2_t b) + /// A64: FMULX Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 MultiplyExtended(Vector64 left, Vector64 right) => MultiplyExtended(left, right); + + /// + /// float64x2_t vmulxq_f64 (float64x2_t a, float64x2_t b) + /// A64: FMULX Vd.2D, Vn.2D, Vm.2D + /// + public static Vector128 MultiplyExtended(Vector128 left, Vector128 right) => MultiplyExtended(left, right); + + /// + /// float32x4_t vmulxq_f32 (float32x4_t a, float32x4_t b) + /// A64: FMULX Vd.4S, Vn.4S, Vm.4S + /// + public static Vector128 MultiplyExtended(Vector128 left, Vector128 right) => MultiplyExtended(left, right); + + /// + /// float64x1_t vmulx_f64 (float64x1_t a, float64x1_t b) + /// A64: FMULX Dd, Dn, Dm + /// + public static Vector64 MultiplyExtendedScalar(Vector64 left, Vector64 right) => MultiplyExtendedScalar(left, right); + + /// + /// float32_t vmulxs_f32 (float32_t a, float32_t b) + /// A64: FMULX Sd, Sn, Sm + /// + public static Vector64 MultiplyExtendedScalar(Vector64 left, Vector64 right) => MultiplyExtendedScalar(left, right); + /// /// float64x2_t vnegq_f64 (float64x2_t a) /// A64: FNEG Vd.2D, Vn.2D @@ -1004,6 +1034,90 @@ internal Arm64() { } /// public static Vector64 NegateScalar(Vector64 value) => NegateScalar(value); + /// + /// float64x2_t vrecpeq_f64 (float64x2_t a) + /// A64: FRECPE Vd.2D, Vn.2D + /// + public static Vector128 ReciprocalEstimate(Vector128 value) => ReciprocalEstimate(value); + + /// + /// float64x1_t vrecpe_f64 (float64x1_t a) + /// A64: FRECPE Dd, Dn + /// + public static Vector64 ReciprocalEstimateScalar(Vector64 value) => ReciprocalEstimateScalar(value); + + /// + /// float32_t vrecpes_f32 (float32_t a) + /// A64: FRECPE Sd, Sn + /// + public static Vector64 ReciprocalEstimateScalar(Vector64 value) => ReciprocalEstimateScalar(value); + + /// + /// float64_t vrecpxd_f64 (float64_t a) + /// A64: FRECPX Dd, Dn + /// + public static Vector64 ReciprocalExponentScalar(Vector64 value) => ReciprocalExponentScalar(value); + + /// + /// float32_t vrecpxs_f32 (float32_t a) + /// A64: FRECPX Sd, Sn + /// + public static Vector64 ReciprocalExponentScalar(Vector64 value) => ReciprocalExponentScalar(value); + + /// + /// float64x2_t vrsqrteq_f64 (float64x2_t a) + /// A64: FRSQRTE Vd.2D, Vn.2D + /// + public static Vector128 ReciprocalSquareRootEstimate(Vector128 value) => ReciprocalSquareRootEstimate(value); + + /// + /// float64x1_t vrsqrte_f64 (float64x1_t a) + /// A64: FRSQRTE Dd, Dn + /// + public static Vector64 ReciprocalSquareRootEstimateScalar(Vector64 value) => ReciprocalSquareRootEstimateScalar(value); + + /// + /// float32_t vrsqrtes_f32 (float32_t a) + /// A64: FRSQRTE Sd, Sn + /// + public static Vector64 ReciprocalSquareRootEstimateScalar(Vector64 value) => ReciprocalSquareRootEstimateScalar(value); + + /// + /// float64x2_t vrsqrtsq_f64 (float64x2_t a, float64x2_t b) + /// A64: FRSQRTS Vd.2D, Vn.2D, Vm.2D + /// + public static Vector128 ReciprocalSquareRootStep(Vector128 left, Vector128 right) => ReciprocalSquareRootStep(left, right); + + /// + /// float64x1_t vrsqrts_f64 (float64x1_t a, float64x1_t b) + /// A64: FRSQRTS Dd, Dn, Dm + /// + public static Vector64 ReciprocalSquareRootStepScalar(Vector64 left, Vector64 right) => ReciprocalSquareRootStepScalar(left, right); + + /// + /// float32_t vrsqrtss_f32 (float32_t a, float32_t b) + /// A64: FRSQRTS Sd, Sn, Sm + /// + public static Vector64 ReciprocalSquareRootStepScalar(Vector64 left, Vector64 right) => ReciprocalSquareRootStepScalar(left, right); + + /// + /// float64x2_t vrecpsq_f64 (float64x2_t a, float64x2_t b) + /// A64: FRECPS Vd.2D, Vn.2D, Vm.2D + /// + public static Vector128 ReciprocalStep(Vector128 left, Vector128 right) => ReciprocalStep(left, right); + + /// + /// float64x1_t vrecps_f64 (float64x1_t a, float64x1_t b) + /// A64: FRECPS Dd, Dn, Dm + /// + public static Vector64 ReciprocalStepScalar(Vector64 left, Vector64 right) => ReciprocalStepScalar(left, right); + + /// + /// float32_t vrecpss_f32 (float32_t a, float32_t b) + /// A64: FRECPS Sd, Sn, Sm + /// + public static Vector64 ReciprocalStepScalar(Vector64 left, Vector64 right) => ReciprocalStepScalar(left, right); + /// /// float32x2_t vsqrt_f32 (float32x2_t a) /// A64: FSQRT Vd.2S, Vn.2S @@ -1902,6 +2016,90 @@ internal Arm64() { } /// public static Vector128 AbsoluteDifference(Vector128 left, Vector128 right) => AbsoluteDifference(left, right); + /// + /// uint8x8_t vaba_u8 (uint8x8_t a, uint8x8_t b, uint8x8_t c) + /// A32: VABA.U8 Dd, Dn, Dm + /// A64: UABA Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 AbsoluteDifferenceAdd(Vector64 addend, Vector64 left, Vector64 right) => AbsoluteDifferenceAdd(addend, left, right); + + /// + /// int16x4_t vaba_s16 (int16x4_t a, int16x4_t b, int16x4_t c) + /// A32: VABA.S16 Dd, Dn, Dm + /// A64: SABA Vd.4H, Vn.4H, Vm.4H + /// + public static Vector64 AbsoluteDifferenceAdd(Vector64 addend, Vector64 left, Vector64 right) => AbsoluteDifferenceAdd(addend, left, right); + + /// + /// int32x2_t vaba_s32 (int32x2_t a, int32x2_t b, int32x2_t c) + /// A32: VABA.S32 Dd, Dn, Dm + /// A64: SABA Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 AbsoluteDifferenceAdd(Vector64 addend, Vector64 left, Vector64 right) => AbsoluteDifferenceAdd(addend, left, right); + + /// + /// int8x8_t vaba_s8 (int8x8_t a, int8x8_t b, int8x8_t c) + /// A32: VABA.S8 Dd, Dn, Dm + /// A64: SABA Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 AbsoluteDifferenceAdd(Vector64 addend, Vector64 left, Vector64 right) => AbsoluteDifferenceAdd(addend, left, right); + + /// + /// uint16x4_t vaba_u16 (uint16x4_t a, uint16x4_t b, uint16x4_t c) + /// A32: VABA.U16 Dd, Dn, Dm + /// A64: UABA Vd.4H, Vn.4H, Vm.4H + /// + public static Vector64 AbsoluteDifferenceAdd(Vector64 addend, Vector64 left, Vector64 right) => AbsoluteDifferenceAdd(addend, left, right); + + /// + /// uint32x2_t vaba_u32 (uint32x2_t a, uint32x2_t b, uint32x2_t c) + /// A32: VABA.U32 Dd, Dn, Dm + /// A64: UABA Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 AbsoluteDifferenceAdd(Vector64 addend, Vector64 left, Vector64 right) => AbsoluteDifferenceAdd(addend, left, right); + + /// + /// uint8x16_t vabaq_u8 (uint8x16_t a, uint8x16_t b, uint8x16_t c) + /// A32: VABA.U8 Qd, Qn, Qm + /// A64: UABA Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 AbsoluteDifferenceAdd(Vector128 addend, Vector128 left, Vector128 right) => AbsoluteDifferenceAdd(addend, left, right); + + /// + /// int16x8_t vabaq_s16 (int16x8_t a, int16x8_t b, int16x8_t c) + /// A32: VABA.S16 Qd, Qn, Qm + /// A64: SABA Vd.8H, Vn.8H, Vm.8H + /// + public static Vector128 AbsoluteDifferenceAdd(Vector128 addend, Vector128 left, Vector128 right) => AbsoluteDifferenceAdd(addend, left, right); + + /// + /// int32x4_t vabaq_s32 (int32x4_t a, int32x4_t b, int32x4_t c) + /// A32: VABA.S32 Qd, Qn, Qm + /// A64: SABA Vd.4S, Vn.4S, Vm.4S + /// + public static Vector128 AbsoluteDifferenceAdd(Vector128 addend, Vector128 left, Vector128 right) => AbsoluteDifferenceAdd(addend, left, right); + + /// + /// int8x16_t vabaq_s8 (int8x16_t a, int8x16_t b, int8x16_t c) + /// A32: VABA.S8 Qd, Qn, Qm + /// A64: SABA Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 AbsoluteDifferenceAdd(Vector128 addend, Vector128 left, Vector128 right) => AbsoluteDifferenceAdd(addend, left, right); + + /// + /// uint16x8_t vabaq_u16 (uint16x8_t a, uint16x8_t b, uint16x8_t c) + /// A32: VABA.U16 Qd, Qn, Qm + /// A64: UABA Vd.8H, Vn.8H, Vm.8H + /// + public static Vector128 AbsoluteDifferenceAdd(Vector128 addend, Vector128 left, Vector128 right) => AbsoluteDifferenceAdd(addend, left, right); + + /// + /// uint32x4_t vabaq_u32 (uint32x4_t a, uint32x4_t b, uint32x4_t c) + /// A32: VABA.U32 Qd, Qn, Qm + /// A64: UABA Vd.4S, Vn.4S, Vm.4S + /// + public static Vector128 AbsoluteDifferenceAdd(Vector128 addend, Vector128 left, Vector128 right) => AbsoluteDifferenceAdd(addend, left, right); + /// /// uint8x8_t vadd_u8 (uint8x8_t a, uint8x8_t b) /// A32: VADD.I8 Dd, Dn, Dm @@ -4615,6 +4813,34 @@ internal Arm64() { } /// public static Vector128 OrNot(Vector128 left, Vector128 right) => OrNot(left, right); + /// + /// poly8x8_t vmul_p8 (poly8x8_t a, poly8x8_t b) + /// A32: VMUL.P8 Dd, Dn, Dm + /// A64: PMUL Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 PolynomialMultiply(Vector64 left, Vector64 right) => PolynomialMultiply(left, right); + + /// + /// poly8x8_t vmul_p8 (poly8x8_t a, poly8x8_t b) + /// A32: VMUL.P8 Dd, Dn, Dm + /// A64: PMUL Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 PolynomialMultiply(Vector64 left, Vector64 right) => PolynomialMultiply(left, right); + + /// + /// poly8x16_t vmulq_p8 (poly8x16_t a, poly8x16_t b) + /// A32: VMUL.P8 Qd, Qn, Qm + /// A64: PMUL Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 PolynomialMultiply(Vector128 left, Vector128 right) => PolynomialMultiply(left, right); + + /// + /// poly8x16_t vmulq_p8 (poly8x16_t a, poly8x16_t b) + /// A32: VMUL.P8 Qd, Qn, Qm + /// A64: PMUL Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 PolynomialMultiply(Vector128 left, Vector128 right) => PolynomialMultiply(left, right); + /// /// uint8x8_t vcnt_u8 (uint8x8_t a) /// A32: VCNT.I8 Dd, Dm @@ -4643,6 +4869,90 @@ internal Arm64() { } /// public static Vector128 PopCount(Vector128 value) => PopCount(value); + /// + /// float32x2_t vrecpe_f32 (float32x2_t a) + /// A32: VRECPE.F32 Dd, Dm + /// A64: FRECPE Vd.2S, Vn.2S + /// + public static Vector64 ReciprocalEstimate(Vector64 value) => ReciprocalEstimate(value); + + /// + /// uint32x2_t vrecpe_u32 (uint32x2_t a) + /// A32: VRECPE.U32 Dd, Dm + /// A64: URECPE Vd.2S, Vn.2S + /// + public static Vector64 ReciprocalEstimate(Vector64 value) => ReciprocalEstimate(value); + + /// + /// float32x4_t vrecpeq_f32 (float32x4_t a) + /// A32: VRECPE.F32 Qd, Qm + /// A64: FRECPE Vd.4S, Vn.4S + /// + public static Vector128 ReciprocalEstimate(Vector128 value) => ReciprocalEstimate(value); + + /// + /// uint32x4_t vrecpeq_u32 (uint32x4_t a) + /// A32: VRECPE.U32 Qd, Qm + /// A64: URECPE Vd.4S, Vn.4S + /// + public static Vector128 ReciprocalEstimate(Vector128 value) => ReciprocalEstimate(value); + + /// + /// float32x2_t vrsqrte_f32 (float32x2_t a) + /// A32: VRSQRTE.F32 Dd, Dm + /// A64: FRSQRTE Vd.2S, Vn.2S + /// + public static Vector64 ReciprocalSquareRootEstimate(Vector64 value) => ReciprocalSquareRootEstimate(value); + + /// + /// uint32x2_t vrsqrte_u32 (uint32x2_t a) + /// A32: VRSQRTE.U32 Dd, Dm + /// A64: URSQRTE Vd.2S, Vn.2S + /// + public static Vector64 ReciprocalSquareRootEstimate(Vector64 value) => ReciprocalSquareRootEstimate(value); + + /// + /// float32x4_t vrsqrteq_f32 (float32x4_t a) + /// A32: VRSQRTE.F32 Qd, Qm + /// A64: FRSQRTE Vd.4S, Vn.4S + /// + public static Vector128 ReciprocalSquareRootEstimate(Vector128 value) => ReciprocalSquareRootEstimate(value); + + /// + /// uint32x4_t vrsqrteq_u32 (uint32x4_t a) + /// A32: VRSQRTE.U32 Qd, Qm + /// A64: URSQRTE Vd.4S, Vn.4S + /// + public static Vector128 ReciprocalSquareRootEstimate(Vector128 value) => ReciprocalSquareRootEstimate(value); + + /// + /// float32x2_t vrsqrts_f32 (float32x2_t a, float32x2_t b) + /// A32: VRSQRTS.F32 Dd, Dn, Dm + /// A64: FRSQRTS Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 ReciprocalSquareRootStep(Vector64 left, Vector64 right) => ReciprocalSquareRootStep(left, right); + + /// + /// float32x4_t vrsqrtsq_f32 (float32x4_t a, float32x4_t b) + /// A32: VRSQRTS.F32 Qd, Qn, Qm + /// A64: FRSQRTS Vd.4S, Vn.4S, Vm.4S + /// + public static Vector128 ReciprocalSquareRootStep(Vector128 left, Vector128 right) => ReciprocalSquareRootStep(left, right); + + /// + /// float32x2_t vrecps_f32 (float32x2_t a, float32x2_t b) + /// A32: VRECPS.F32 Dd, Dn, Dm + /// A64: FRECPS Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 ReciprocalStep(Vector64 left, Vector64 right) => ReciprocalStep(left, right); + + /// + /// float32x4_t vrecpsq_f32 (float32x4_t a, float32x4_t b) + /// A32: VRECPS.F32 Qd, Qn, Qm + /// A64: FRECPS Vd.4S, Vn.4S, Vm.4S + /// + public static Vector128 ReciprocalStep(Vector128 left, Vector128 right) => ReciprocalStep(left, right); + /// /// float64x1_t vsqrt_f64 (float64x1_t a) /// A32: VSQRT.F64 Dd, Dm diff --git a/src/libraries/System.Runtime.Intrinsics.Experimental/ref/System.Runtime.Intrinsics.Experimental.cs b/src/libraries/System.Runtime.Intrinsics.Experimental/ref/System.Runtime.Intrinsics.Experimental.cs index 16f106bab39179..0a8ac48f56bef1 100644 --- a/src/libraries/System.Runtime.Intrinsics.Experimental/ref/System.Runtime.Intrinsics.Experimental.cs +++ b/src/libraries/System.Runtime.Intrinsics.Experimental/ref/System.Runtime.Intrinsics.Experimental.cs @@ -42,6 +42,18 @@ internal AdvSimd() { } public static System.Runtime.Intrinsics.Vector64 AbsoluteDifference(System.Runtime.Intrinsics.Vector64 left, System.Runtime.Intrinsics.Vector64 right) { throw null; } public static System.Runtime.Intrinsics.Vector64 AbsoluteDifference(System.Runtime.Intrinsics.Vector64 left, System.Runtime.Intrinsics.Vector64 right) { throw null; } public static System.Runtime.Intrinsics.Vector64 AbsoluteDifference(System.Runtime.Intrinsics.Vector64 left, System.Runtime.Intrinsics.Vector64 right) { throw null; } + public static System.Runtime.Intrinsics.Vector128 AbsoluteDifferenceAdd(System.Runtime.Intrinsics.Vector128 addend, System.Runtime.Intrinsics.Vector128 left, System.Runtime.Intrinsics.Vector128 right) { throw null; } + public static System.Runtime.Intrinsics.Vector128 AbsoluteDifferenceAdd(System.Runtime.Intrinsics.Vector128 addend, System.Runtime.Intrinsics.Vector128 left, System.Runtime.Intrinsics.Vector128 right) { throw null; } + public static System.Runtime.Intrinsics.Vector128 AbsoluteDifferenceAdd(System.Runtime.Intrinsics.Vector128 addend, System.Runtime.Intrinsics.Vector128 left, System.Runtime.Intrinsics.Vector128 right) { throw null; } + public static System.Runtime.Intrinsics.Vector128 AbsoluteDifferenceAdd(System.Runtime.Intrinsics.Vector128 addend, System.Runtime.Intrinsics.Vector128 left, System.Runtime.Intrinsics.Vector128 right) { throw null; } + public static System.Runtime.Intrinsics.Vector128 AbsoluteDifferenceAdd(System.Runtime.Intrinsics.Vector128 addend, System.Runtime.Intrinsics.Vector128 left, System.Runtime.Intrinsics.Vector128 right) { throw null; } + public static System.Runtime.Intrinsics.Vector128 AbsoluteDifferenceAdd(System.Runtime.Intrinsics.Vector128 addend, System.Runtime.Intrinsics.Vector128 left, System.Runtime.Intrinsics.Vector128 right) { throw null; } + public static System.Runtime.Intrinsics.Vector64 AbsoluteDifferenceAdd(System.Runtime.Intrinsics.Vector64 addend, System.Runtime.Intrinsics.Vector64 left, System.Runtime.Intrinsics.Vector64 right) { throw null; } + public static System.Runtime.Intrinsics.Vector64 AbsoluteDifferenceAdd(System.Runtime.Intrinsics.Vector64 addend, System.Runtime.Intrinsics.Vector64 left, System.Runtime.Intrinsics.Vector64 right) { throw null; } + public static System.Runtime.Intrinsics.Vector64 AbsoluteDifferenceAdd(System.Runtime.Intrinsics.Vector64 addend, System.Runtime.Intrinsics.Vector64 left, System.Runtime.Intrinsics.Vector64 right) { throw null; } + public static System.Runtime.Intrinsics.Vector64 AbsoluteDifferenceAdd(System.Runtime.Intrinsics.Vector64 addend, System.Runtime.Intrinsics.Vector64 left, System.Runtime.Intrinsics.Vector64 right) { throw null; } + public static System.Runtime.Intrinsics.Vector64 AbsoluteDifferenceAdd(System.Runtime.Intrinsics.Vector64 addend, System.Runtime.Intrinsics.Vector64 left, System.Runtime.Intrinsics.Vector64 right) { throw null; } + public static System.Runtime.Intrinsics.Vector64 AbsoluteDifferenceAdd(System.Runtime.Intrinsics.Vector64 addend, System.Runtime.Intrinsics.Vector64 left, System.Runtime.Intrinsics.Vector64 right) { throw null; } public static System.Runtime.Intrinsics.Vector64 AbsScalar(System.Runtime.Intrinsics.Vector64 value) { throw null; } public static System.Runtime.Intrinsics.Vector64 AbsScalar(System.Runtime.Intrinsics.Vector64 value) { throw null; } public static System.Runtime.Intrinsics.Vector128 Add(System.Runtime.Intrinsics.Vector128 left, System.Runtime.Intrinsics.Vector128 right) { throw null; } @@ -427,10 +439,26 @@ internal AdvSimd() { } public static System.Runtime.Intrinsics.Vector64 OrNot(System.Runtime.Intrinsics.Vector64 left, System.Runtime.Intrinsics.Vector64 right) { throw null; } public static System.Runtime.Intrinsics.Vector64 OrNot(System.Runtime.Intrinsics.Vector64 left, System.Runtime.Intrinsics.Vector64 right) { throw null; } public static System.Runtime.Intrinsics.Vector64 OrNot(System.Runtime.Intrinsics.Vector64 left, System.Runtime.Intrinsics.Vector64 right) { throw null; } + public static System.Runtime.Intrinsics.Vector128 PolynomialMultiply(System.Runtime.Intrinsics.Vector128 left, System.Runtime.Intrinsics.Vector128 right) { throw null; } + public static System.Runtime.Intrinsics.Vector128 PolynomialMultiply(System.Runtime.Intrinsics.Vector128 left, System.Runtime.Intrinsics.Vector128 right) { throw null; } + public static System.Runtime.Intrinsics.Vector64 PolynomialMultiply(System.Runtime.Intrinsics.Vector64 left, System.Runtime.Intrinsics.Vector64 right) { throw null; } + public static System.Runtime.Intrinsics.Vector64 PolynomialMultiply(System.Runtime.Intrinsics.Vector64 left, System.Runtime.Intrinsics.Vector64 right) { throw null; } public static System.Runtime.Intrinsics.Vector128 PopCount(System.Runtime.Intrinsics.Vector128 value) { throw null; } public static System.Runtime.Intrinsics.Vector128 PopCount(System.Runtime.Intrinsics.Vector128 value) { throw null; } public static System.Runtime.Intrinsics.Vector64 PopCount(System.Runtime.Intrinsics.Vector64 value) { throw null; } public static System.Runtime.Intrinsics.Vector64 PopCount(System.Runtime.Intrinsics.Vector64 value) { throw null; } + public static System.Runtime.Intrinsics.Vector128 ReciprocalEstimate(System.Runtime.Intrinsics.Vector128 value) { throw null; } + public static System.Runtime.Intrinsics.Vector128 ReciprocalEstimate(System.Runtime.Intrinsics.Vector128 value) { throw null; } + public static System.Runtime.Intrinsics.Vector64 ReciprocalEstimate(System.Runtime.Intrinsics.Vector64 value) { throw null; } + public static System.Runtime.Intrinsics.Vector64 ReciprocalEstimate(System.Runtime.Intrinsics.Vector64 value) { throw null; } + public static System.Runtime.Intrinsics.Vector128 ReciprocalSquareRootEstimate(System.Runtime.Intrinsics.Vector128 value) { throw null; } + public static System.Runtime.Intrinsics.Vector128 ReciprocalSquareRootEstimate(System.Runtime.Intrinsics.Vector128 value) { throw null; } + public static System.Runtime.Intrinsics.Vector64 ReciprocalSquareRootEstimate(System.Runtime.Intrinsics.Vector64 value) { throw null; } + public static System.Runtime.Intrinsics.Vector64 ReciprocalSquareRootEstimate(System.Runtime.Intrinsics.Vector64 value) { throw null; } + public static System.Runtime.Intrinsics.Vector128 ReciprocalSquareRootStep(System.Runtime.Intrinsics.Vector128 left, System.Runtime.Intrinsics.Vector128 right) { throw null; } + public static System.Runtime.Intrinsics.Vector64 ReciprocalSquareRootStep(System.Runtime.Intrinsics.Vector64 left, System.Runtime.Intrinsics.Vector64 right) { throw null; } + public static System.Runtime.Intrinsics.Vector128 ReciprocalStep(System.Runtime.Intrinsics.Vector128 left, System.Runtime.Intrinsics.Vector128 right) { throw null; } + public static System.Runtime.Intrinsics.Vector64 ReciprocalStep(System.Runtime.Intrinsics.Vector64 left, System.Runtime.Intrinsics.Vector64 right) { throw null; } public static System.Runtime.Intrinsics.Vector64 SqrtScalar(System.Runtime.Intrinsics.Vector64 value) { throw null; } public static System.Runtime.Intrinsics.Vector64 SqrtScalar(System.Runtime.Intrinsics.Vector64 value) { throw null; } public static System.Runtime.Intrinsics.Vector128 Subtract(System.Runtime.Intrinsics.Vector128 left, System.Runtime.Intrinsics.Vector128 right) { throw null; } @@ -629,9 +657,28 @@ internal Arm64() { } public static System.Runtime.Intrinsics.Vector64 MinScalar(System.Runtime.Intrinsics.Vector64 left, System.Runtime.Intrinsics.Vector64 right) { throw null; } public static System.Runtime.Intrinsics.Vector64 MinScalar(System.Runtime.Intrinsics.Vector64 left, System.Runtime.Intrinsics.Vector64 right) { throw null; } public static System.Runtime.Intrinsics.Vector128 Multiply(System.Runtime.Intrinsics.Vector128 left, System.Runtime.Intrinsics.Vector128 right) { throw null; } + public static System.Runtime.Intrinsics.Vector128 MultiplyExtended(System.Runtime.Intrinsics.Vector128 left, System.Runtime.Intrinsics.Vector128 right) { throw null; } + public static System.Runtime.Intrinsics.Vector128 MultiplyExtended(System.Runtime.Intrinsics.Vector128 left, System.Runtime.Intrinsics.Vector128 right) { throw null; } + public static System.Runtime.Intrinsics.Vector64 MultiplyExtended(System.Runtime.Intrinsics.Vector64 left, System.Runtime.Intrinsics.Vector64 right) { throw null; } + public static System.Runtime.Intrinsics.Vector64 MultiplyExtendedScalar(System.Runtime.Intrinsics.Vector64 left, System.Runtime.Intrinsics.Vector64 right) { throw null; } + public static System.Runtime.Intrinsics.Vector64 MultiplyExtendedScalar(System.Runtime.Intrinsics.Vector64 left, System.Runtime.Intrinsics.Vector64 right) { throw null; } public static System.Runtime.Intrinsics.Vector128 Negate(System.Runtime.Intrinsics.Vector128 value) { throw null; } public static System.Runtime.Intrinsics.Vector128 Negate(System.Runtime.Intrinsics.Vector128 value) { throw null; } public static System.Runtime.Intrinsics.Vector64 NegateScalar(System.Runtime.Intrinsics.Vector64 value) { throw null; } + public static System.Runtime.Intrinsics.Vector128 ReciprocalEstimate(System.Runtime.Intrinsics.Vector128 value) { throw null; } + public static System.Runtime.Intrinsics.Vector64 ReciprocalEstimateScalar(System.Runtime.Intrinsics.Vector64 value) { throw null; } + public static System.Runtime.Intrinsics.Vector64 ReciprocalEstimateScalar(System.Runtime.Intrinsics.Vector64 value) { throw null; } + public static System.Runtime.Intrinsics.Vector64 ReciprocalExponentScalar(System.Runtime.Intrinsics.Vector64 value) { throw null; } + public static System.Runtime.Intrinsics.Vector64 ReciprocalExponentScalar(System.Runtime.Intrinsics.Vector64 value) { throw null; } + public static System.Runtime.Intrinsics.Vector128 ReciprocalSquareRootEstimate(System.Runtime.Intrinsics.Vector128 value) { throw null; } + public static System.Runtime.Intrinsics.Vector64 ReciprocalSquareRootEstimateScalar(System.Runtime.Intrinsics.Vector64 value) { throw null; } + public static System.Runtime.Intrinsics.Vector64 ReciprocalSquareRootEstimateScalar(System.Runtime.Intrinsics.Vector64 value) { throw null; } + public static System.Runtime.Intrinsics.Vector128 ReciprocalSquareRootStep(System.Runtime.Intrinsics.Vector128 left, System.Runtime.Intrinsics.Vector128 right) { throw null; } + public static System.Runtime.Intrinsics.Vector64 ReciprocalSquareRootStepScalar(System.Runtime.Intrinsics.Vector64 left, System.Runtime.Intrinsics.Vector64 right) { throw null; } + public static System.Runtime.Intrinsics.Vector64 ReciprocalSquareRootStepScalar(System.Runtime.Intrinsics.Vector64 left, System.Runtime.Intrinsics.Vector64 right) { throw null; } + public static System.Runtime.Intrinsics.Vector128 ReciprocalStep(System.Runtime.Intrinsics.Vector128 left, System.Runtime.Intrinsics.Vector128 right) { throw null; } + public static System.Runtime.Intrinsics.Vector64 ReciprocalStepScalar(System.Runtime.Intrinsics.Vector64 left, System.Runtime.Intrinsics.Vector64 right) { throw null; } + public static System.Runtime.Intrinsics.Vector64 ReciprocalStepScalar(System.Runtime.Intrinsics.Vector64 left, System.Runtime.Intrinsics.Vector64 right) { throw null; } public static System.Runtime.Intrinsics.Vector128 ReverseElementBits(System.Runtime.Intrinsics.Vector128 value) { throw null; } public static System.Runtime.Intrinsics.Vector128 ReverseElementBits(System.Runtime.Intrinsics.Vector128 value) { throw null; } public static System.Runtime.Intrinsics.Vector64 ReverseElementBits(System.Runtime.Intrinsics.Vector64 value) { throw null; }