diff --git a/src/coreclr/src/jit/gentree.cpp b/src/coreclr/src/jit/gentree.cpp index 08a993d8856c93..5394144a941da3 100644 --- a/src/coreclr/src/jit/gentree.cpp +++ b/src/coreclr/src/jit/gentree.cpp @@ -711,13 +711,13 @@ int GenTree::GetRegisterDstCount(Compiler* compiler) const } #endif -#if defined(TARGET_XARCH) && defined(FEATURE_HW_INTRINSICS) - if (OperIs(GT_HWINTRINSIC)) + if (OperIsHWIntrinsic()) { assert(TypeGet() == TYP_STRUCT); + // TODO-ARM64-NYI: Support hardware intrinsics operating on multiple contiguous registers. return 2; } -#endif + if (OperIsScalarLocal()) { return AsLclVar()->GetFieldCount(compiler); diff --git a/src/coreclr/src/jit/gentree.h b/src/coreclr/src/jit/gentree.h index 6e74955d61473f..07ae1c37aee730 100644 --- a/src/coreclr/src/jit/gentree.h +++ b/src/coreclr/src/jit/gentree.h @@ -7243,12 +7243,12 @@ inline bool GenTree::IsMultiRegNode() const return true; } #endif // FEATURE_MULTIREG_RET -#if defined(TARGET_XARCH) && defined(FEATURE_HW_INTRINSICS) - if (OperIs(GT_HWINTRINSIC)) + + if (OperIsHWIntrinsic()) { return (TypeGet() == TYP_STRUCT); } -#endif + if (IsMultiRegLclVar()) { return true; @@ -7291,13 +7291,13 @@ inline unsigned GenTree::GetMultiRegCount() return AsCopyOrReload()->GetRegCount(); } #endif // FEATURE_MULTIREG_RET -#if defined(TARGET_XARCH) && defined(FEATURE_HW_INTRINSICS) - if (OperIs(GT_HWINTRINSIC)) + + if (OperIsHWIntrinsic()) { assert(TypeGet() == TYP_STRUCT); return 2; } -#endif + if (OperIs(GT_LCL_VAR, GT_STORE_LCL_VAR)) { assert((gtFlags & GTF_VAR_MULTIREG) != 0); @@ -7360,10 +7360,11 @@ inline regNumber GenTree::GetRegByIndex(int regIndex) return AsCopyOrReload()->GetRegNumByIdx(regIndex); } #endif // FEATURE_MULTIREG_RET -#if defined(TARGET_XARCH) && defined(FEATURE_HW_INTRINSICS) +#ifdef FEATURE_HW_INTRINSICS if (OperIs(GT_HWINTRINSIC)) { assert(regIndex == 1); + // TODO-ARM64-NYI: Support hardware intrinsics operating on multiple contiguous registers. return AsHWIntrinsic()->GetOtherReg(); } #endif @@ -7417,15 +7418,27 @@ inline var_types GenTree::GetRegTypeByIndex(int regIndex) #endif // FEATURE_MULTIREG_RET -#if defined(TARGET_XARCH) && defined(FEATURE_HW_INTRINSICS) - if (OperIs(GT_HWINTRINSIC)) + if (OperIsHWIntrinsic()) { + assert(TypeGet() == TYP_STRUCT); + +#ifdef TARGET_XARCH // At this time, the only multi-reg HW intrinsics all return the type of their // arguments. If this changes, we will need a way to record or determine this. - assert(TypeGet() == TYP_STRUCT); return gtGetOp1()->TypeGet(); - } +#elif defined(TARGET_ARM64) + if (AsHWIntrinsic()->gtSIMDSize == 16) + { + return TYP_SIMD16; + } + else + { + assert(AsHWIntrinsic()->gtSIMDSize == 8); + return TYP_SIMD8; + } #endif + } + if (OperIs(GT_LCL_VAR, GT_STORE_LCL_VAR)) { if (TypeGet() == TYP_LONG) diff --git a/src/coreclr/src/jit/hwintrinsic.cpp b/src/coreclr/src/jit/hwintrinsic.cpp index 5723ac8f322b41..30644716c30007 100644 --- a/src/coreclr/src/jit/hwintrinsic.cpp +++ b/src/coreclr/src/jit/hwintrinsic.cpp @@ -785,16 +785,30 @@ GenTree* Compiler::impHWIntrinsic(NamedIntrinsic intrinsic, if ((retType == TYP_STRUCT) && featureSIMD) { - unsigned int sizeBytes; - baseType = getBaseTypeAndSizeOfSIMDType(sig->retTypeSigClass, &sizeBytes); - retType = getSIMDTypeForSize(sizeBytes); - assert(sizeBytes != 0); - - // We want to return early here for cases where retType was TYP_STRUCT as per method signature and - // rather than deferring the decision after getting the baseType of arg. - if (!isSupportedBaseType(intrinsic, baseType)) + unsigned int sizeBytes = 0; + baseType = getBaseTypeAndSizeOfSIMDType(sig->retTypeSigClass, &sizeBytes); + + if (sizeBytes != 0) { - return nullptr; + // We want to return early here for cases where retType was TYP_STRUCT as per method signature and + // rather than deferring the decision after getting the baseType of arg. + if (!isSupportedBaseType(intrinsic, baseType)) + { + return nullptr; + } + + retType = getSIMDTypeForSize(sizeBytes); + } + else + { +#ifdef TARGET_ARM64 + assert((intrinsic == NI_AdvSimd_Arm64_LoadPairScalarVector64) || + (intrinsic == NI_AdvSimd_Arm64_LoadPairScalarVector64NonTemporal) || + (intrinsic == NI_AdvSimd_Arm64_LoadPairVector64) || + (intrinsic == NI_AdvSimd_Arm64_LoadPairVector64NonTemporal) || + (intrinsic == NI_AdvSimd_Arm64_LoadPairVector128) || + (intrinsic == NI_AdvSimd_Arm64_LoadPairVector128NonTemporal)); +#endif } } diff --git a/src/coreclr/src/jit/hwintrinsicarm64.cpp b/src/coreclr/src/jit/hwintrinsicarm64.cpp index 0d0021b0b8c65d..fae0c79a9c2275 100644 --- a/src/coreclr/src/jit/hwintrinsicarm64.cpp +++ b/src/coreclr/src/jit/hwintrinsicarm64.cpp @@ -502,10 +502,24 @@ GenTree* Compiler::impSpecialIntrinsic(NamedIntrinsic intrinsic, break; } - default: + case NI_AdvSimd_Arm64_LoadPairScalarVector64: + case NI_AdvSimd_Arm64_LoadPairScalarVector64NonTemporal: + case NI_AdvSimd_Arm64_LoadPairVector64: + case NI_AdvSimd_Arm64_LoadPairVector64NonTemporal: + case NI_AdvSimd_Arm64_LoadPairVector128: + case NI_AdvSimd_Arm64_LoadPairVector128NonTemporal: { - return nullptr; + assert(retType == TYP_STRUCT); + assert(numArgs == 1); + op1 = impPopStack().val; + GenTreeHWIntrinsic* hwintrin = gtNewSimdHWIntrinsicNode(retType, op1, intrinsic, baseType, simdSize); + hwintrin->SetLayout(typGetObjLayout(sig->retTypeSigClass)); + retNode = hwintrin; + break; } + + default: + return nullptr; } return retNode; diff --git a/src/coreclr/src/jit/hwintrinsiccodegenarm64.cpp b/src/coreclr/src/jit/hwintrinsiccodegenarm64.cpp index 5b2fd24a53912a..1916cc3aed91df 100644 --- a/src/coreclr/src/jit/hwintrinsiccodegenarm64.cpp +++ b/src/coreclr/src/jit/hwintrinsiccodegenarm64.cpp @@ -701,6 +701,18 @@ void CodeGen::genHWIntrinsic(GenTreeHWIntrinsic* node) } break; + case NI_AdvSimd_Arm64_LoadPairVector128: + case NI_AdvSimd_Arm64_LoadPairVector128NonTemporal: + case NI_AdvSimd_Arm64_LoadPairVector64: + case NI_AdvSimd_Arm64_LoadPairVector64NonTemporal: + GetEmitter()->emitIns_R_R_R(ins, emitSize, targetReg, node->GetOtherReg(), op1Reg); + break; + + case NI_AdvSimd_Arm64_LoadPairScalarVector64: + case NI_AdvSimd_Arm64_LoadPairScalarVector64NonTemporal: + GetEmitter()->emitIns_R_R_R(ins, emitTypeSize(intrin.baseType), targetReg, node->GetOtherReg(), op1Reg); + break; + case NI_AdvSimd_Store: GetEmitter()->emitIns_R_R(ins, emitSize, op2Reg, op1Reg, opt); break; diff --git a/src/coreclr/src/jit/hwintrinsiclistarm64.h b/src/coreclr/src/jit/hwintrinsiclistarm64.h index 6de9ca2b158b1e..dbf4f1f665268e 100644 --- a/src/coreclr/src/jit/hwintrinsiclistarm64.h +++ b/src/coreclr/src/jit/hwintrinsiclistarm64.h @@ -419,6 +419,12 @@ HARDWARE_INTRINSIC(AdvSimd_Arm64, FusedMultiplySubtractBySelectedScalar, HARDWARE_INTRINSIC(AdvSimd_Arm64, FusedMultiplySubtractScalarBySelectedScalar, 8, 4, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_fmls, INS_fmls}, HW_Category_SIMDByIndexedElement, HW_Flag_HasImmediateOperand|HW_Flag_HasRMWSemantics|HW_Flag_SIMDScalar) HARDWARE_INTRINSIC(AdvSimd_Arm64, InsertSelectedScalar, -1, 4, {INS_ins, INS_ins, INS_ins, INS_ins, INS_ins, INS_ins, INS_ins, INS_ins, INS_ins, INS_ins}, HW_Category_SIMD, HW_Flag_HasImmediateOperand|HW_Flag_HasRMWSemantics|HW_Flag_NoJmpTableIMM|HW_Flag_SIMDScalar|HW_Flag_SpecialCodeGen) HARDWARE_INTRINSIC(AdvSimd_Arm64, LoadAndReplicateToVector128, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_ld1r, INS_ld1r, INS_invalid, INS_ld1r}, HW_Category_MemoryLoad, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AdvSimd_Arm64, LoadPairScalarVector64, 8, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_ldp, INS_ldp, INS_invalid, INS_invalid, INS_ldp, INS_invalid}, HW_Category_MemoryLoad, HW_Flag_BaseTypeFromFirstArg|HW_Flag_SpecialImport|HW_Flag_SpecialCodeGen) +HARDWARE_INTRINSIC(AdvSimd_Arm64, LoadPairScalarVector64NonTemporal, 8, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_ldnp, INS_ldnp, INS_invalid, INS_invalid, INS_ldnp, INS_invalid}, HW_Category_MemoryLoad, HW_Flag_BaseTypeFromFirstArg|HW_Flag_SpecialImport|HW_Flag_SpecialCodeGen) +HARDWARE_INTRINSIC(AdvSimd_Arm64, LoadPairVector64, 8, 1, {INS_ldp, INS_ldp, INS_ldp, INS_ldp, INS_ldp, INS_ldp, INS_ldp, INS_ldp, INS_ldp, INS_ldp}, HW_Category_MemoryLoad, HW_Flag_BaseTypeFromFirstArg|HW_Flag_SpecialImport|HW_Flag_SpecialCodeGen) +HARDWARE_INTRINSIC(AdvSimd_Arm64, LoadPairVector64NonTemporal, 8, 1, {INS_ldnp, INS_ldnp, INS_ldnp, INS_ldnp, INS_ldnp, INS_ldnp, INS_ldnp, INS_ldnp, INS_ldnp, INS_ldnp}, HW_Category_MemoryLoad, HW_Flag_BaseTypeFromFirstArg|HW_Flag_SpecialImport|HW_Flag_SpecialCodeGen) +HARDWARE_INTRINSIC(AdvSimd_Arm64, LoadPairVector128, 16, 1, {INS_ldp, INS_ldp, INS_ldp, INS_ldp, INS_ldp, INS_ldp, INS_ldp, INS_ldp, INS_ldp, INS_ldp}, HW_Category_MemoryLoad, HW_Flag_BaseTypeFromFirstArg|HW_Flag_SpecialImport|HW_Flag_SpecialCodeGen) +HARDWARE_INTRINSIC(AdvSimd_Arm64, LoadPairVector128NonTemporal, 16, 1, {INS_ldnp, INS_ldnp, INS_ldnp, INS_ldnp, INS_ldnp, INS_ldnp, INS_ldnp, INS_ldnp, INS_ldnp, INS_ldnp}, HW_Category_MemoryLoad, HW_Flag_BaseTypeFromFirstArg|HW_Flag_SpecialImport|HW_Flag_SpecialCodeGen) HARDWARE_INTRINSIC(AdvSimd_Arm64, Max, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_fmax}, HW_Category_SIMD, HW_Flag_Commutative) HARDWARE_INTRINSIC(AdvSimd_Arm64, MaxAcross, -1, 1, {INS_smaxv, INS_umaxv, INS_smaxv, INS_umaxv, INS_smaxv, INS_umaxv, INS_invalid, INS_invalid, INS_fmaxv, INS_invalid}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) HARDWARE_INTRINSIC(AdvSimd_Arm64, MaxNumber, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_fmaxnm}, HW_Category_SIMD, HW_Flag_Commutative) diff --git a/src/coreclr/src/jit/importer.cpp b/src/coreclr/src/jit/importer.cpp index 5d57941ba41077..658d8de1dcc590 100644 --- a/src/coreclr/src/jit/importer.cpp +++ b/src/coreclr/src/jit/importer.cpp @@ -1281,7 +1281,7 @@ GenTree* Compiler::impAssignStructPtr(GenTree* destAddr, } assert(src->OperIs(GT_LCL_VAR, GT_LCL_FLD, GT_FIELD, GT_IND, GT_OBJ, GT_CALL, GT_MKREFANY, GT_RET_EXPR, GT_COMMA) || - (src->TypeGet() != TYP_STRUCT && src->OperIsSimdOrHWintrinsic())); + src->OperIsSimdOrHWintrinsic()); var_types asgType = src->TypeGet(); diff --git a/src/coreclr/src/jit/lower.cpp b/src/coreclr/src/jit/lower.cpp index 7a090b5a3c73af..caa3df89982cd8 100644 --- a/src/coreclr/src/jit/lower.cpp +++ b/src/coreclr/src/jit/lower.cpp @@ -6178,10 +6178,10 @@ bool Lowering::CheckMultiRegLclVar(GenTreeLclVar* lclNode, const ReturnTypeDesc* } } #ifdef TARGET_XARCH - // For local stores on XARCH we only handle mismatched src/dest register count for - // calls of SIMD type. If the source was another lclVar similarly promoted, we would + // For local stores on XARCH we can't handle another lclVar source. + // If the source was another lclVar similarly promoted, we would // have broken it into multiple stores. - if (lclNode->OperIs(GT_STORE_LCL_VAR) && !lclNode->gtGetOp1()->OperIs(GT_CALL)) + if (lclNode->OperIs(GT_STORE_LCL_VAR) && lclNode->gtGetOp1()->OperIs(GT_LCL_VAR)) { canEnregister = false; } diff --git a/src/coreclr/src/jit/lowerxarch.cpp b/src/coreclr/src/jit/lowerxarch.cpp index a1211814951357..76ec5e8db77f0c 100644 --- a/src/coreclr/src/jit/lowerxarch.cpp +++ b/src/coreclr/src/jit/lowerxarch.cpp @@ -218,6 +218,16 @@ void Lowering::LowerBlockStore(GenTreeBlk* blkNode) #endif } } + else if (src->OperIsHWIntrinsic()) + { + assert(!blkNode->AsObj()->GetLayout()->HasGCPtr()); + if (blkNode->OperIs(GT_STORE_OBJ)) + { + blkNode->SetOper(GT_STORE_BLK); + } + blkNode->gtBlkOpKind = GenTreeBlk::BlkOpKindUnroll; + ContainBlockStoreAddress(blkNode, size, dstAddr); + } else { assert(src->OperIs(GT_IND, GT_LCL_VAR, GT_LCL_FLD)); diff --git a/src/coreclr/src/jit/lsra.cpp b/src/coreclr/src/jit/lsra.cpp index b09b45d2fffd01..bb2cfc082b1b9b 100644 --- a/src/coreclr/src/jit/lsra.cpp +++ b/src/coreclr/src/jit/lsra.cpp @@ -152,7 +152,7 @@ void lsraAssignRegToTree(GenTree* tree, regNumber reg, unsigned regIdx) putArg->SetRegNumByIdx(reg, regIdx); } #endif // FEATURE_ARG_SPLIT -#if defined(TARGET_XARCH) && defined(FEATURE_HW_INTRINSICS) +#ifdef FEATURE_HW_INTRINSICS else if (tree->OperIs(GT_HWINTRINSIC)) { assert(regIdx == 1); diff --git a/src/coreclr/src/jit/lsra.h b/src/coreclr/src/jit/lsra.h index c2adcf29a40a27..ef78103662a242 100644 --- a/src/coreclr/src/jit/lsra.h +++ b/src/coreclr/src/jit/lsra.h @@ -1068,7 +1068,7 @@ class LinearScan : public LinearScanInterface var_types type = tree->TypeGet(); if (type == TYP_STRUCT) { - assert(tree->OperIs(GT_LCL_VAR, GT_STORE_LCL_VAR)); + assert(tree->OperIs(GT_LCL_VAR, GT_STORE_LCL_VAR) || tree->OperIsHWIntrinsic()); GenTreeLclVar* lclVar = tree->AsLclVar(); LclVarDsc* varDsc = compiler->lvaGetDesc(lclVar); type = varDsc->GetRegisterType(lclVar); @@ -1613,7 +1613,7 @@ class LinearScan : public LinearScanInterface #endif // FEATURE_SIMD #ifdef FEATURE_HW_INTRINSICS - int BuildHWIntrinsic(GenTreeHWIntrinsic* intrinsicTree); + int BuildHWIntrinsic(GenTreeHWIntrinsic* intrinsicTree, int* pDstCount); #endif // FEATURE_HW_INTRINSICS int BuildPutArgStk(GenTreePutArgStk* argNode); diff --git a/src/coreclr/src/jit/lsraarm64.cpp b/src/coreclr/src/jit/lsraarm64.cpp index 9c67a05cc55657..a8f4cfe3aa96c1 100644 --- a/src/coreclr/src/jit/lsraarm64.cpp +++ b/src/coreclr/src/jit/lsraarm64.cpp @@ -345,7 +345,7 @@ int LinearScan::BuildNode(GenTree* tree) #ifdef FEATURE_HW_INTRINSICS case GT_HWINTRINSIC: - srcCount = BuildHWIntrinsic(tree->AsHWIntrinsic()); + srcCount = BuildHWIntrinsic(tree->AsHWIntrinsic(), &dstCount); break; #endif // FEATURE_HW_INTRINSICS @@ -944,17 +944,39 @@ int LinearScan::BuildSIMD(GenTreeSIMD* simdTree) // // Arguments: // tree - The GT_HWINTRINSIC node of interest +// pDstCount - OUT parameter - the number of registers defined for the given node // // Return Value: // The number of sources consumed by this node. // -int LinearScan::BuildHWIntrinsic(GenTreeHWIntrinsic* intrinsicTree) +int LinearScan::BuildHWIntrinsic(GenTreeHWIntrinsic* intrinsicTree, int* pDstCount) { + assert(pDstCount != nullptr); + const HWIntrinsic intrin(intrinsicTree); int srcCount = 0; int dstCount = intrinsicTree->IsValue() ? 1 : 0; + switch (intrinsicTree->gtHWIntrinsicId) + { + // TODO-Arm64-Cleanup: Hardware intrinsics that operate on multiple contigious registers + // would require more cases like these and, perhaps, we should look at a way to encode + // the information in the intrinsics table using declarative approach. + case NI_AdvSimd_Arm64_LoadPairScalarVector64: + case NI_AdvSimd_Arm64_LoadPairScalarVector64NonTemporal: + case NI_AdvSimd_Arm64_LoadPairVector64: + case NI_AdvSimd_Arm64_LoadPairVector64NonTemporal: + case NI_AdvSimd_Arm64_LoadPairVector128: + case NI_AdvSimd_Arm64_LoadPairVector128NonTemporal: + dstCount = 2; + break; + + default: + assert(intrinsicTree->TypeGet() != TYP_STRUCT); + break; + } + const bool hasImmediateOperand = HWIntrinsicInfo::HasImmediateOperand(intrin.id); if (hasImmediateOperand && !HWIntrinsicInfo::NoJmpTableImm(intrin.id)) @@ -1197,15 +1219,21 @@ int LinearScan::BuildHWIntrinsic(GenTreeHWIntrinsic* intrinsicTree) buildInternalRegisterUses(); - if (dstCount == 1) + if ((dstCount == 1) || (dstCount == 2)) { BuildDef(intrinsicTree); + + if (dstCount == 2) + { + BuildDef(intrinsicTree, RBM_NONE, 1); + } } else { assert(dstCount == 0); } + *pDstCount = dstCount; return srcCount; } #endif diff --git a/src/coreclr/src/jit/lsraxarch.cpp b/src/coreclr/src/jit/lsraxarch.cpp index db787c55fdf282..f13ac834a934ad 100644 --- a/src/coreclr/src/jit/lsraxarch.cpp +++ b/src/coreclr/src/jit/lsraxarch.cpp @@ -342,7 +342,7 @@ int LinearScan::BuildNode(GenTree* tree) #ifdef FEATURE_HW_INTRINSICS case GT_HWINTRINSIC: - srcCount = BuildHWIntrinsic(tree->AsHWIntrinsic()); + srcCount = BuildHWIntrinsic(tree->AsHWIntrinsic(), &dstCount); break; #endif // FEATURE_HW_INTRINSICS @@ -1352,7 +1352,7 @@ int LinearScan::BuildBlockStore(GenTreeBlk* blkNode) dstAddrRegMask = RBM_RDI; srcRegMask = RBM_RSI; } - else + else if (!src->OperIsHWIntrinsic()) { switch (blkNode->gtBlkOpKind) { @@ -1423,7 +1423,16 @@ int LinearScan::BuildBlockStore(GenTreeBlk* blkNode) useCount += BuildAddrUses(dstAddr); } - if (srcAddrOrFill != nullptr) + if (src->IsMultiRegNode()) + { + int srcCount = src->GetMultiRegCount(); + for (int i = 0; i < srcCount; ++i) + { + BuildUse(src, RBM_NONE, i); + } + useCount += srcCount; + } + else if (srcAddrOrFill != nullptr) { if (!srcAddrOrFill->isContained()) { @@ -2160,12 +2169,15 @@ int LinearScan::BuildSIMD(GenTreeSIMD* simdTree) // // Arguments: // tree - The GT_HWINTRINSIC node of interest +// pDstCount - OUT parameter - the number of registers defined for the given node // // Return Value: // The number of sources consumed by this node. // -int LinearScan::BuildHWIntrinsic(GenTreeHWIntrinsic* intrinsicTree) +int LinearScan::BuildHWIntrinsic(GenTreeHWIntrinsic* intrinsicTree, int* pDstCount) { + assert(pDstCount != nullptr); + NamedIntrinsic intrinsicId = intrinsicTree->gtHWIntrinsicId; var_types baseType = intrinsicTree->gtSIMDBaseType; CORINFO_InstructionSet isa = HWIntrinsicInfo::lookupIsa(intrinsicId); @@ -2588,15 +2600,17 @@ int LinearScan::BuildHWIntrinsic(GenTreeHWIntrinsic* intrinsicTree) buildInternalRegisterUses(); } - if (dstCount == 1) + assert(dstCount <= 2); + if (dstCount != 0) { BuildDef(intrinsicTree, dstCandidates); - } - else - { - assert(dstCount == 0); + if (dstCount == 2) + { + BuildDef(intrinsicTree, dstCandidates, 1); + } } + *pDstCount = dstCount; return srcCount; } #endif diff --git a/src/coreclr/src/jit/morph.cpp b/src/coreclr/src/jit/morph.cpp index 25d6bfbd81aacc..4407d42bef732f 100644 --- a/src/coreclr/src/jit/morph.cpp +++ b/src/coreclr/src/jit/morph.cpp @@ -10356,7 +10356,7 @@ GenTree* Compiler::fgMorphBlockOperand(GenTree* tree, var_types asgType, unsigne } } } - else + else if (!effectiveVal->OperIsHWIntrinsic()) { GenTreeIndir* indirTree = nullptr; GenTreeLclVarCommon* lclNode = nullptr; @@ -10772,11 +10772,10 @@ GenTree* Compiler::fgMorphCopyBlock(GenTree* tree) } #endif // TARGET_ARM - // Can't use field by field assignment if the src is a call. - if (src->OperGet() == GT_CALL) + // Can't use field by field assignment if the src is a call or HW intrinsic. + if (src->OperIs(GT_CALL) || src->OperIsHWIntrinsic()) { - JITDUMP(" src is a call"); - // C++ style CopyBlock with holes + JITDUMP(" src is a call or hw intrinsic"); requiresCopyBlock = true; } 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 2fcc2efcfc9cad..d53236e7116da8 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 @@ -1567,6 +1567,236 @@ internal Arm64() { } /// public static unsafe Vector128 LoadAndReplicateToVector128(ulong* address) { throw new PlatformNotSupportedException(); } + /// + /// A64: LDP Dt1, Dt2, [Xn] + /// + public static unsafe (Vector64 Value1, Vector64 Value2) LoadPairVector64(byte* address) { throw new PlatformNotSupportedException(); } + + /// + /// A64: LDP Dt1, Dt2, [Xn] + /// + public static unsafe (Vector64 Value1, Vector64 Value2) LoadPairVector64(double* address) { throw new PlatformNotSupportedException(); } + + /// + /// A64: LDP Dt1, Dt2, [Xn] + /// + public static unsafe (Vector64 Value1, Vector64 Value2) LoadPairVector64(short* address) { throw new PlatformNotSupportedException(); } + + /// + /// A64: LDP Dt1, Dt2, [Xn] + /// + public static unsafe (Vector64 Value1, Vector64 Value2) LoadPairVector64(int* address) { throw new PlatformNotSupportedException(); } + + /// + /// A64: LDP Dt1, Dt2, [Xn] + /// + public static unsafe (Vector64 Value1, Vector64 Value2) LoadPairVector64(long* address) { throw new PlatformNotSupportedException(); } + + /// + /// A64: LDP Dt1, Dt2, [Xn] + /// + public static unsafe (Vector64 Value1, Vector64 Value2) LoadPairVector64(sbyte* address) { throw new PlatformNotSupportedException(); } + + /// + /// A64: LDP Dt1, Dt2, [Xn] + /// + public static unsafe (Vector64 Value1, Vector64 Value2) LoadPairVector64(float* address) { throw new PlatformNotSupportedException(); } + + /// + /// A64: LDP Dt1, Dt2, [Xn] + /// + public static unsafe (Vector64 Value1, Vector64 Value2) LoadPairVector64(ushort* address) { throw new PlatformNotSupportedException(); } + + /// + /// A64: LDP Dt1, Dt2, [Xn] + /// + public static unsafe (Vector64 Value1, Vector64 Value2) LoadPairVector64(uint* address) { throw new PlatformNotSupportedException(); } + + /// + /// A64: LDP Dt1, Dt2, [Xn] + /// + public static unsafe (Vector64 Value1, Vector64 Value2) LoadPairVector64(ulong* address) { throw new PlatformNotSupportedException(); } + + /// + /// A64: LDP St1, St2, [Xn] + /// + public static unsafe (Vector64 Value1, Vector64 Value2) LoadPairScalarVector64(int* address) { throw new PlatformNotSupportedException(); } + + /// + /// A64: LDP St1, St2, [Xn] + /// + public static unsafe (Vector64 Value1, Vector64 Value2) LoadPairScalarVector64(float* address) { throw new PlatformNotSupportedException(); } + + /// + /// A64: LDP St1, St2, [Xn] + /// + public static unsafe (Vector64 Value1, Vector64 Value2) LoadPairScalarVector64(uint* address) { throw new PlatformNotSupportedException(); } + + /// + /// A64: LDP Qt1, Qt2, [Xn] + /// + public static unsafe (Vector128 Value1, Vector128 Value2) LoadPairVector128(byte* address) { throw new PlatformNotSupportedException(); } + + /// + /// A64: LDP Qt1, Qt2, [Xn] + /// + public static unsafe (Vector128 Value1, Vector128 Value2) LoadPairVector128(double* address) { throw new PlatformNotSupportedException(); } + + /// + /// A64: LDP Qt1, Qt2, [Xn] + /// + public static unsafe (Vector128 Value1, Vector128 Value2) LoadPairVector128(short* address) { throw new PlatformNotSupportedException(); } + + /// + /// A64: LDP Qt1, Qt2, [Xn] + /// + public static unsafe (Vector128 Value1, Vector128 Value2) LoadPairVector128(int* address) { throw new PlatformNotSupportedException(); } + + /// + /// A64: LDP Qt1, Qt2, [Xn] + /// + public static unsafe (Vector128 Value1, Vector128 Value2) LoadPairVector128(long* address) { throw new PlatformNotSupportedException(); } + + /// + /// A64: LDP Qt1, Qt2, [Xn] + /// + public static unsafe (Vector128 Value1, Vector128 Value2) LoadPairVector128(sbyte* address) { throw new PlatformNotSupportedException(); } + + /// + /// A64: LDP Qt1, Qt2, [Xn] + /// + public static unsafe (Vector128 Value1, Vector128 Value2) LoadPairVector128(float* address) { throw new PlatformNotSupportedException(); } + + /// + /// A64: LDP Qt1, Qt2, [Xn] + /// + public static unsafe (Vector128 Value1, Vector128 Value2) LoadPairVector128(ushort* address) { throw new PlatformNotSupportedException(); } + + /// + /// A64: LDP Qt1, Qt2, [Xn] + /// + public static unsafe (Vector128 Value1, Vector128 Value2) LoadPairVector128(uint* address) { throw new PlatformNotSupportedException(); } + + /// + /// A64: LDP Qt1, Qt2, [Xn] + /// + public static unsafe (Vector128 Value1, Vector128 Value2) LoadPairVector128(ulong* address) { throw new PlatformNotSupportedException(); } + + /// + /// A64: LDNP Dt1, Dt2, [Xn] + /// + public static unsafe (Vector64 Value1, Vector64 Value2) LoadPairVector64NonTemporal(byte* address) { throw new PlatformNotSupportedException(); } + + /// + /// A64: LDNP Dt1, Dt2, [Xn] + /// + public static unsafe (Vector64 Value1, Vector64 Value2) LoadPairVector64NonTemporal(double* address) { throw new PlatformNotSupportedException(); } + + /// + /// A64: LDNP Dt1, Dt2, [Xn] + /// + public static unsafe (Vector64 Value1, Vector64 Value2) LoadPairVector64NonTemporal(short* address) { throw new PlatformNotSupportedException(); } + + /// + /// A64: LDNP Dt1, Dt2, [Xn] + /// + public static unsafe (Vector64 Value1, Vector64 Value2) LoadPairVector64NonTemporal(int* address) { throw new PlatformNotSupportedException(); } + + /// + /// A64: LDNP Dt1, Dt2, [Xn] + /// + public static unsafe (Vector64 Value1, Vector64 Value2) LoadPairVector64NonTemporal(long* address) { throw new PlatformNotSupportedException(); } + + /// + /// A64: LDNP Dt1, Dt2, [Xn] + /// + public static unsafe (Vector64 Value1, Vector64 Value2) LoadPairVector64NonTemporal(sbyte* address) { throw new PlatformNotSupportedException(); } + + /// + /// A64: LDNP Dt1, Dt2, [Xn] + /// + public static unsafe (Vector64 Value1, Vector64 Value2) LoadPairVector64NonTemporal(float* address) { throw new PlatformNotSupportedException(); } + + /// + /// A64: LDNP Dt1, Dt2, [Xn] + /// + public static unsafe (Vector64 Value1, Vector64 Value2) LoadPairVector64NonTemporal(ushort* address) { throw new PlatformNotSupportedException(); } + + /// + /// A64: LDNP Dt1, Dt2, [Xn] + /// + public static unsafe (Vector64 Value1, Vector64 Value2) LoadPairVector64NonTemporal(uint* address) { throw new PlatformNotSupportedException(); } + + /// + /// A64: LDNP Dt1, Dt2, [Xn] + /// + public static unsafe (Vector64 Value1, Vector64 Value2) LoadPairVector64NonTemporal(ulong* address) { throw new PlatformNotSupportedException(); } + + /// + /// A64: LDNP St1, St2, [Xn] + /// + public static unsafe (Vector64 Value1, Vector64 Value2) LoadPairScalarVector64NonTemporal(int* address) { throw new PlatformNotSupportedException(); } + + /// + /// A64: LDNP St1, St2, [Xn] + /// + public static unsafe (Vector64 Value1, Vector64 Value2) LoadPairScalarVector64NonTemporal(float* address) { throw new PlatformNotSupportedException(); } + + /// + /// A64: LDNP St1, St2, [Xn] + /// + public static unsafe (Vector64 Value1, Vector64 Value2) LoadPairScalarVector64NonTemporal(uint* address) { throw new PlatformNotSupportedException(); } + + /// + /// A64: LDNP Qt1, Qt2, [Xn] + /// + public static unsafe (Vector128 Value1, Vector128 Value2) LoadPairVector128NonTemporal(byte* address) { throw new PlatformNotSupportedException(); } + + /// + /// A64: LDNP Qt1, Qt2, [Xn] + /// + public static unsafe (Vector128 Value1, Vector128 Value2) LoadPairVector128NonTemporal(double* address) { throw new PlatformNotSupportedException(); } + + /// + /// A64: LDNP Qt1, Qt2, [Xn] + /// + public static unsafe (Vector128 Value1, Vector128 Value2) LoadPairVector128NonTemporal(short* address) { throw new PlatformNotSupportedException(); } + + /// + /// A64: LDNP Qt1, Qt2, [Xn] + /// + public static unsafe (Vector128 Value1, Vector128 Value2) LoadPairVector128NonTemporal(int* address) { throw new PlatformNotSupportedException(); } + + /// + /// A64: LDNP Qt1, Qt2, [Xn] + /// + public static unsafe (Vector128 Value1, Vector128 Value2) LoadPairVector128NonTemporal(long* address) { throw new PlatformNotSupportedException(); } + + /// + /// A64: LDNP Qt1, Qt2, [Xn] + /// + public static unsafe (Vector128 Value1, Vector128 Value2) LoadPairVector128NonTemporal(sbyte* address) { throw new PlatformNotSupportedException(); } + + /// + /// A64: LDNP Qt1, Qt2, [Xn] + /// + public static unsafe (Vector128 Value1, Vector128 Value2) LoadPairVector128NonTemporal(float* address) { throw new PlatformNotSupportedException(); } + + /// + /// A64: LDNP Qt1, Qt2, [Xn] + /// + public static unsafe (Vector128 Value1, Vector128 Value2) LoadPairVector128NonTemporal(ushort* address) { throw new PlatformNotSupportedException(); } + + /// + /// A64: LDNP Qt1, Qt2, [Xn] + /// + public static unsafe (Vector128 Value1, Vector128 Value2) LoadPairVector128NonTemporal(uint* address) { throw new PlatformNotSupportedException(); } + + /// + /// A64: LDNP Qt1, Qt2, [Xn] + /// + public static unsafe (Vector128 Value1, Vector128 Value2) LoadPairVector128NonTemporal(ulong* address) { throw new PlatformNotSupportedException(); } + /// /// float64x2_t vmaxq_f64 (float64x2_t a, float64x2_t b) /// A64: FMAX Vd.2D, Vn.2D, Vm.2D 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 a8db248ef75c22..11177c4fd59ee5 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 @@ -1565,6 +1565,236 @@ internal Arm64() { } /// public static unsafe Vector128 LoadAndReplicateToVector128(ulong* address) => LoadAndReplicateToVector128(address); + /// + /// A64: LDP Dt1, Dt2, [Xn] + /// + public static unsafe (Vector64 Value1, Vector64 Value2) LoadPairVector64(byte* address) => LoadPairVector64(address); + + /// + /// A64: LDP Dt1, Dt2, [Xn] + /// + public static unsafe (Vector64 Value1, Vector64 Value2) LoadPairVector64(double* address) => LoadPairVector64(address); + + /// + /// A64: LDP Dt1, Dt2, [Xn] + /// + public static unsafe (Vector64 Value1, Vector64 Value2) LoadPairVector64(short* address) => LoadPairVector64(address); + + /// + /// A64: LDP Dt1, Dt2, [Xn] + /// + public static unsafe (Vector64 Value1, Vector64 Value2) LoadPairVector64(int* address) => LoadPairVector64(address); + + /// + /// A64: LDP Dt1, Dt2, [Xn] + /// + public static unsafe (Vector64 Value1, Vector64 Value2) LoadPairVector64(long* address) => LoadPairVector64(address); + + /// + /// A64: LDP Dt1, Dt2, [Xn] + /// + public static unsafe (Vector64 Value1, Vector64 Value2) LoadPairVector64(sbyte* address) => LoadPairVector64(address); + + /// + /// A64: LDP Dt1, Dt2, [Xn] + /// + public static unsafe (Vector64 Value1, Vector64 Value2) LoadPairVector64(float* address) => LoadPairVector64(address); + + /// + /// A64: LDP Dt1, Dt2, [Xn] + /// + public static unsafe (Vector64 Value1, Vector64 Value2) LoadPairVector64(ushort* address) => LoadPairVector64(address); + + /// + /// A64: LDP Dt1, Dt2, [Xn] + /// + public static unsafe (Vector64 Value1, Vector64 Value2) LoadPairVector64(uint* address) => LoadPairVector64(address); + + /// + /// A64: LDP Dt1, Dt2, [Xn] + /// + public static unsafe (Vector64 Value1, Vector64 Value2) LoadPairVector64(ulong* address) => LoadPairVector64(address); + + /// + /// A64: LDP St1, St2, [Xn] + /// + public static unsafe (Vector64 Value1, Vector64 Value2) LoadPairScalarVector64(int* address) => LoadPairScalarVector64(address); + + /// + /// A64: LDP St1, St2, [Xn] + /// + public static unsafe (Vector64 Value1, Vector64 Value2) LoadPairScalarVector64(float* address) => LoadPairScalarVector64(address); + + /// + /// A64: LDP St1, St2, [Xn] + /// + public static unsafe (Vector64 Value1, Vector64 Value2) LoadPairScalarVector64(uint* address) => LoadPairScalarVector64(address); + + /// + /// A64: LDP Qt1, Qt2, [Xn] + /// + public static unsafe (Vector128 Value1, Vector128 Value2) LoadPairVector128(byte* address) => LoadPairVector128(address); + + /// + /// A64: LDP Qt1, Qt2, [Xn] + /// + public static unsafe (Vector128 Value1, Vector128 Value2) LoadPairVector128(double* address) => LoadPairVector128(address); + + /// + /// A64: LDP Qt1, Qt2, [Xn] + /// + public static unsafe (Vector128 Value1, Vector128 Value2) LoadPairVector128(short* address) => LoadPairVector128(address); + + /// + /// A64: LDP Qt1, Qt2, [Xn] + /// + public static unsafe (Vector128 Value1, Vector128 Value2) LoadPairVector128(int* address) => LoadPairVector128(address); + + /// + /// A64: LDP Qt1, Qt2, [Xn] + /// + public static unsafe (Vector128 Value1, Vector128 Value2) LoadPairVector128(long* address) => LoadPairVector128(address); + + /// + /// A64: LDP Qt1, Qt2, [Xn] + /// + public static unsafe (Vector128 Value1, Vector128 Value2) LoadPairVector128(sbyte* address) => LoadPairVector128(address); + + /// + /// A64: LDP Qt1, Qt2, [Xn] + /// + public static unsafe (Vector128 Value1, Vector128 Value2) LoadPairVector128(float* address) => LoadPairVector128(address); + + /// + /// A64: LDP Qt1, Qt2, [Xn] + /// + public static unsafe (Vector128 Value1, Vector128 Value2) LoadPairVector128(ushort* address) => LoadPairVector128(address); + + /// + /// A64: LDP Qt1, Qt2, [Xn] + /// + public static unsafe (Vector128 Value1, Vector128 Value2) LoadPairVector128(uint* address) => LoadPairVector128(address); + + /// + /// A64: LDP Qt1, Qt2, [Xn] + /// + public static unsafe (Vector128 Value1, Vector128 Value2) LoadPairVector128(ulong* address) => LoadPairVector128(address); + + /// + /// A64: LDNP Dt1, Dt2, [Xn] + /// + public static unsafe (Vector64 Value1, Vector64 Value2) LoadPairVector64NonTemporal(byte* address) => LoadPairVector64NonTemporal(address); + + /// + /// A64: LDNP Dt1, Dt2, [Xn] + /// + public static unsafe (Vector64 Value1, Vector64 Value2) LoadPairVector64NonTemporal(double* address) => LoadPairVector64NonTemporal(address); + + /// + /// A64: LDNP Dt1, Dt2, [Xn] + /// + public static unsafe (Vector64 Value1, Vector64 Value2) LoadPairVector64NonTemporal(short* address) => LoadPairVector64NonTemporal(address); + + /// + /// A64: LDNP Dt1, Dt2, [Xn] + /// + public static unsafe (Vector64 Value1, Vector64 Value2) LoadPairVector64NonTemporal(int* address) => LoadPairVector64NonTemporal(address); + + /// + /// A64: LDNP Dt1, Dt2, [Xn] + /// + public static unsafe (Vector64 Value1, Vector64 Value2) LoadPairVector64NonTemporal(long* address) => LoadPairVector64NonTemporal(address); + + /// + /// A64: LDNP Dt1, Dt2, [Xn] + /// + public static unsafe (Vector64 Value1, Vector64 Value2) LoadPairVector64NonTemporal(sbyte* address) => LoadPairVector64NonTemporal(address); + + /// + /// A64: LDNP Dt1, Dt2, [Xn] + /// + public static unsafe (Vector64 Value1, Vector64 Value2) LoadPairVector64NonTemporal(float* address) => LoadPairVector64NonTemporal(address); + + /// + /// A64: LDNP Dt1, Dt2, [Xn] + /// + public static unsafe (Vector64 Value1, Vector64 Value2) LoadPairVector64NonTemporal(ushort* address) => LoadPairVector64NonTemporal(address); + + /// + /// A64: LDNP Dt1, Dt2, [Xn] + /// + public static unsafe (Vector64 Value1, Vector64 Value2) LoadPairVector64NonTemporal(uint* address) => LoadPairVector64NonTemporal(address); + + /// + /// A64: LDNP Dt1, Dt2, [Xn] + /// + public static unsafe (Vector64 Value1, Vector64 Value2) LoadPairVector64NonTemporal(ulong* address) => LoadPairVector64NonTemporal(address); + + /// + /// A64: LDNP St1, St2, [Xn] + /// + public static unsafe (Vector64 Value1, Vector64 Value2) LoadPairScalarVector64NonTemporal(int* address) => LoadPairScalarVector64NonTemporal(address); + + /// + /// A64: LDNP St1, St2, [Xn] + /// + public static unsafe (Vector64 Value1, Vector64 Value2) LoadPairScalarVector64NonTemporal(float* address) => LoadPairScalarVector64NonTemporal(address); + + /// + /// A64: LDNP St1, St2, [Xn] + /// + public static unsafe (Vector64 Value1, Vector64 Value2) LoadPairScalarVector64NonTemporal(uint* address) => LoadPairScalarVector64NonTemporal(address); + + /// + /// A64: LDNP Qt1, Qt2, [Xn] + /// + public static unsafe (Vector128 Value1, Vector128 Value2) LoadPairVector128NonTemporal(byte* address) => LoadPairVector128NonTemporal(address); + + /// + /// A64: LDNP Qt1, Qt2, [Xn] + /// + public static unsafe (Vector128 Value1, Vector128 Value2) LoadPairVector128NonTemporal(double* address) => LoadPairVector128NonTemporal(address); + + /// + /// A64: LDNP Qt1, Qt2, [Xn] + /// + public static unsafe (Vector128 Value1, Vector128 Value2) LoadPairVector128NonTemporal(short* address) => LoadPairVector128NonTemporal(address); + + /// + /// A64: LDNP Qt1, Qt2, [Xn] + /// + public static unsafe (Vector128 Value1, Vector128 Value2) LoadPairVector128NonTemporal(int* address) => LoadPairVector128NonTemporal(address); + + /// + /// A64: LDNP Qt1, Qt2, [Xn] + /// + public static unsafe (Vector128 Value1, Vector128 Value2) LoadPairVector128NonTemporal(long* address) => LoadPairVector128NonTemporal(address); + + /// + /// A64: LDNP Qt1, Qt2, [Xn] + /// + public static unsafe (Vector128 Value1, Vector128 Value2) LoadPairVector128NonTemporal(sbyte* address) => LoadPairVector128NonTemporal(address); + + /// + /// A64: LDNP Qt1, Qt2, [Xn] + /// + public static unsafe (Vector128 Value1, Vector128 Value2) LoadPairVector128NonTemporal(float* address) => LoadPairVector128NonTemporal(address); + + /// + /// A64: LDNP Qt1, Qt2, [Xn] + /// + public static unsafe (Vector128 Value1, Vector128 Value2) LoadPairVector128NonTemporal(ushort* address) => LoadPairVector128NonTemporal(address); + + /// + /// A64: LDNP Qt1, Qt2, [Xn] + /// + public static unsafe (Vector128 Value1, Vector128 Value2) LoadPairVector128NonTemporal(uint* address) => LoadPairVector128NonTemporal(address); + + /// + /// A64: LDNP Qt1, Qt2, [Xn] + /// + public static unsafe (Vector128 Value1, Vector128 Value2) LoadPairVector128NonTemporal(ulong* address) => LoadPairVector128NonTemporal(address); + /// /// float64x2_t vmaxq_f64 (float64x2_t a, float64x2_t b) /// A64: FMAX Vd.2D, Vn.2D, Vm.2D diff --git a/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs b/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs index fbb78cb5533feb..8b7a4a2aad6939 100644 --- a/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs +++ b/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs @@ -2171,6 +2171,52 @@ internal Arm64() { } public unsafe static System.Runtime.Intrinsics.Vector128 LoadAndReplicateToVector128(double* address) { throw null; } public unsafe static System.Runtime.Intrinsics.Vector128 LoadAndReplicateToVector128(long* address) { throw null; } public unsafe static System.Runtime.Intrinsics.Vector128 LoadAndReplicateToVector128(ulong* address) { throw null; } + public unsafe static (System.Runtime.Intrinsics.Vector64 Value1, System.Runtime.Intrinsics.Vector64 Value2) LoadPairScalarVector64(int* address) { throw null; } + public unsafe static (System.Runtime.Intrinsics.Vector64 Value1, System.Runtime.Intrinsics.Vector64 Value2) LoadPairScalarVector64(float* address) { throw null; } + public unsafe static (System.Runtime.Intrinsics.Vector64 Value1, System.Runtime.Intrinsics.Vector64 Value2) LoadPairScalarVector64(uint* address) { throw null; } + public unsafe static (System.Runtime.Intrinsics.Vector64 Value1, System.Runtime.Intrinsics.Vector64 Value2) LoadPairScalarVector64NonTemporal(int* address) { throw null; } + public unsafe static (System.Runtime.Intrinsics.Vector64 Value1, System.Runtime.Intrinsics.Vector64 Value2) LoadPairScalarVector64NonTemporal(float* address) { throw null; } + public unsafe static (System.Runtime.Intrinsics.Vector64 Value1, System.Runtime.Intrinsics.Vector64 Value2) LoadPairScalarVector64NonTemporal(uint* address) { throw null; } + public unsafe static (System.Runtime.Intrinsics.Vector128 Value1, System.Runtime.Intrinsics.Vector128 Value2) LoadPairVector128(byte* address) { throw null; } + public unsafe static (System.Runtime.Intrinsics.Vector128 Value1, System.Runtime.Intrinsics.Vector128 Value2) LoadPairVector128(double* address) { throw null; } + public unsafe static (System.Runtime.Intrinsics.Vector128 Value1, System.Runtime.Intrinsics.Vector128 Value2) LoadPairVector128(short* address) { throw null; } + public unsafe static (System.Runtime.Intrinsics.Vector128 Value1, System.Runtime.Intrinsics.Vector128 Value2) LoadPairVector128(int* address) { throw null; } + public unsafe static (System.Runtime.Intrinsics.Vector128 Value1, System.Runtime.Intrinsics.Vector128 Value2) LoadPairVector128(long* address) { throw null; } + public unsafe static (System.Runtime.Intrinsics.Vector128 Value1, System.Runtime.Intrinsics.Vector128 Value2) LoadPairVector128(sbyte* address) { throw null; } + public unsafe static (System.Runtime.Intrinsics.Vector128 Value1, System.Runtime.Intrinsics.Vector128 Value2) LoadPairVector128(float* address) { throw null; } + public unsafe static (System.Runtime.Intrinsics.Vector128 Value1, System.Runtime.Intrinsics.Vector128 Value2) LoadPairVector128(ushort* address) { throw null; } + public unsafe static (System.Runtime.Intrinsics.Vector128 Value1, System.Runtime.Intrinsics.Vector128 Value2) LoadPairVector128(uint* address) { throw null; } + public unsafe static (System.Runtime.Intrinsics.Vector128 Value1, System.Runtime.Intrinsics.Vector128 Value2) LoadPairVector128(ulong* address) { throw null; } + public unsafe static (System.Runtime.Intrinsics.Vector128 Value1, System.Runtime.Intrinsics.Vector128 Value2) LoadPairVector128NonTemporal(byte* address) { throw null; } + public unsafe static (System.Runtime.Intrinsics.Vector128 Value1, System.Runtime.Intrinsics.Vector128 Value2) LoadPairVector128NonTemporal(double* address) { throw null; } + public unsafe static (System.Runtime.Intrinsics.Vector128 Value1, System.Runtime.Intrinsics.Vector128 Value2) LoadPairVector128NonTemporal(short* address) { throw null; } + public unsafe static (System.Runtime.Intrinsics.Vector128 Value1, System.Runtime.Intrinsics.Vector128 Value2) LoadPairVector128NonTemporal(int* address) { throw null; } + public unsafe static (System.Runtime.Intrinsics.Vector128 Value1, System.Runtime.Intrinsics.Vector128 Value2) LoadPairVector128NonTemporal(long* address) { throw null; } + public unsafe static (System.Runtime.Intrinsics.Vector128 Value1, System.Runtime.Intrinsics.Vector128 Value2) LoadPairVector128NonTemporal(sbyte* address) { throw null; } + public unsafe static (System.Runtime.Intrinsics.Vector128 Value1, System.Runtime.Intrinsics.Vector128 Value2) LoadPairVector128NonTemporal(float* address) { throw null; } + public unsafe static (System.Runtime.Intrinsics.Vector128 Value1, System.Runtime.Intrinsics.Vector128 Value2) LoadPairVector128NonTemporal(ushort* address) { throw null; } + public unsafe static (System.Runtime.Intrinsics.Vector128 Value1, System.Runtime.Intrinsics.Vector128 Value2) LoadPairVector128NonTemporal(uint* address) { throw null; } + public unsafe static (System.Runtime.Intrinsics.Vector128 Value1, System.Runtime.Intrinsics.Vector128 Value2) LoadPairVector128NonTemporal(ulong* address) { throw null; } + public unsafe static (System.Runtime.Intrinsics.Vector64 Value1, System.Runtime.Intrinsics.Vector64 Value2) LoadPairVector64(byte* address) { throw null; } + public unsafe static (System.Runtime.Intrinsics.Vector64 Value1, System.Runtime.Intrinsics.Vector64 Value2) LoadPairVector64(double* address) { throw null; } + public unsafe static (System.Runtime.Intrinsics.Vector64 Value1, System.Runtime.Intrinsics.Vector64 Value2) LoadPairVector64(short* address) { throw null; } + public unsafe static (System.Runtime.Intrinsics.Vector64 Value1, System.Runtime.Intrinsics.Vector64 Value2) LoadPairVector64(int* address) { throw null; } + public unsafe static (System.Runtime.Intrinsics.Vector64 Value1, System.Runtime.Intrinsics.Vector64 Value2) LoadPairVector64(long* address) { throw null; } + public unsafe static (System.Runtime.Intrinsics.Vector64 Value1, System.Runtime.Intrinsics.Vector64 Value2) LoadPairVector64(sbyte* address) { throw null; } + public unsafe static (System.Runtime.Intrinsics.Vector64 Value1, System.Runtime.Intrinsics.Vector64 Value2) LoadPairVector64(float* address) { throw null; } + public unsafe static (System.Runtime.Intrinsics.Vector64 Value1, System.Runtime.Intrinsics.Vector64 Value2) LoadPairVector64(ushort* address) { throw null; } + public unsafe static (System.Runtime.Intrinsics.Vector64 Value1, System.Runtime.Intrinsics.Vector64 Value2) LoadPairVector64(uint* address) { throw null; } + public unsafe static (System.Runtime.Intrinsics.Vector64 Value1, System.Runtime.Intrinsics.Vector64 Value2) LoadPairVector64(ulong* address) { throw null; } + public unsafe static (System.Runtime.Intrinsics.Vector64 Value1, System.Runtime.Intrinsics.Vector64 Value2) LoadPairVector64NonTemporal(byte* address) { throw null; } + public unsafe static (System.Runtime.Intrinsics.Vector64 Value1, System.Runtime.Intrinsics.Vector64 Value2) LoadPairVector64NonTemporal(double* address) { throw null; } + public unsafe static (System.Runtime.Intrinsics.Vector64 Value1, System.Runtime.Intrinsics.Vector64 Value2) LoadPairVector64NonTemporal(short* address) { throw null; } + public unsafe static (System.Runtime.Intrinsics.Vector64 Value1, System.Runtime.Intrinsics.Vector64 Value2) LoadPairVector64NonTemporal(int* address) { throw null; } + public unsafe static (System.Runtime.Intrinsics.Vector64 Value1, System.Runtime.Intrinsics.Vector64 Value2) LoadPairVector64NonTemporal(long* address) { throw null; } + public unsafe static (System.Runtime.Intrinsics.Vector64 Value1, System.Runtime.Intrinsics.Vector64 Value2) LoadPairVector64NonTemporal(sbyte* address) { throw null; } + public unsafe static (System.Runtime.Intrinsics.Vector64 Value1, System.Runtime.Intrinsics.Vector64 Value2) LoadPairVector64NonTemporal(float* address) { throw null; } + public unsafe static (System.Runtime.Intrinsics.Vector64 Value1, System.Runtime.Intrinsics.Vector64 Value2) LoadPairVector64NonTemporal(ushort* address) { throw null; } + public unsafe static (System.Runtime.Intrinsics.Vector64 Value1, System.Runtime.Intrinsics.Vector64 Value2) LoadPairVector64NonTemporal(uint* address) { throw null; } + public unsafe static (System.Runtime.Intrinsics.Vector64 Value1, System.Runtime.Intrinsics.Vector64 Value2) LoadPairVector64NonTemporal(ulong* address) { throw null; } public static System.Runtime.Intrinsics.Vector128 Max(System.Runtime.Intrinsics.Vector128 left, System.Runtime.Intrinsics.Vector128 right) { throw null; } public static System.Runtime.Intrinsics.Vector64 MaxAcross(System.Runtime.Intrinsics.Vector128 value) { throw null; } public static System.Runtime.Intrinsics.Vector64 MaxAcross(System.Runtime.Intrinsics.Vector128 value) { throw null; } diff --git a/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/AdvSimd.Arm64_Part2_r.csproj b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/AdvSimd.Arm64_Part2_r.csproj index 9e5bb852c66c37..8124d4f14f7d33 100644 --- a/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/AdvSimd.Arm64_Part2_r.csproj +++ b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/AdvSimd.Arm64_Part2_r.csproj @@ -46,6 +46,52 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -62,52 +108,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/AdvSimd.Arm64_Part2_ro.csproj b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/AdvSimd.Arm64_Part2_ro.csproj index 0f2b16160a2194..66ee5660a0f9f1 100644 --- a/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/AdvSimd.Arm64_Part2_ro.csproj +++ b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/AdvSimd.Arm64_Part2_ro.csproj @@ -46,6 +46,52 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -62,52 +108,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/AdvSimd.Arm64_Part3_r.csproj b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/AdvSimd.Arm64_Part3_r.csproj index 437f1067d10762..0a5db075b14e71 100644 --- a/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/AdvSimd.Arm64_Part3_r.csproj +++ b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/AdvSimd.Arm64_Part3_r.csproj @@ -8,6 +8,52 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -62,52 +108,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/AdvSimd.Arm64_Part3_ro.csproj b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/AdvSimd.Arm64_Part3_ro.csproj index 13580d32dfa23c..b967739de0e524 100644 --- a/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/AdvSimd.Arm64_Part3_ro.csproj +++ b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/AdvSimd.Arm64_Part3_ro.csproj @@ -8,6 +8,52 @@ True + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -62,52 +108,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/AdvSimd.Arm64_Part4_r.csproj b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/AdvSimd.Arm64_Part4_r.csproj index 143f9a5b8ecd05..10ec5b137683b9 100644 --- a/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/AdvSimd.Arm64_Part4_r.csproj +++ b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/AdvSimd.Arm64_Part4_r.csproj @@ -8,6 +8,52 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -62,52 +108,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/AdvSimd.Arm64_Part4_ro.csproj b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/AdvSimd.Arm64_Part4_ro.csproj index 88cd888f12816d..754009ca65ed40 100644 --- a/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/AdvSimd.Arm64_Part4_ro.csproj +++ b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/AdvSimd.Arm64_Part4_ro.csproj @@ -8,6 +8,52 @@ True + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -62,52 +108,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/AdvSimd.Arm64_Part5_r.csproj b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/AdvSimd.Arm64_Part5_r.csproj index 39e343813daa39..9175e1f1047d1f 100644 --- a/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/AdvSimd.Arm64_Part5_r.csproj +++ b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/AdvSimd.Arm64_Part5_r.csproj @@ -8,6 +8,52 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -62,40 +108,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/AdvSimd.Arm64_Part5_ro.csproj b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/AdvSimd.Arm64_Part5_ro.csproj index 66171e3eb6c9e1..fe864173832a36 100644 --- a/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/AdvSimd.Arm64_Part5_ro.csproj +++ b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/AdvSimd.Arm64_Part5_ro.csproj @@ -8,6 +8,52 @@ True + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -62,40 +108,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/AdvSimd.Arm64_Part6_r.csproj b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/AdvSimd.Arm64_Part6_r.csproj new file mode 100644 index 00000000000000..6d9e4362963e86 --- /dev/null +++ b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/AdvSimd.Arm64_Part6_r.csproj @@ -0,0 +1,49 @@ + + + Exe + true + + + Embedded + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/AdvSimd.Arm64_Part6_ro.csproj b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/AdvSimd.Arm64_Part6_ro.csproj new file mode 100644 index 00000000000000..226486a7c7cdd6 --- /dev/null +++ b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/AdvSimd.Arm64_Part6_ro.csproj @@ -0,0 +1,49 @@ + + + Exe + true + + + Embedded + True + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairScalarVector64.Int32.cs b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairScalarVector64.Int32.cs new file mode 100644 index 00000000000000..f476f38c9f84bd --- /dev/null +++ b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairScalarVector64.Int32.cs @@ -0,0 +1,203 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Reflection; +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 LoadPairScalarVector64_Int32() + { + var test = new LoadPairScalarVector64_Int32(); + + if (test.IsSupported) + { + // Validates basic functionality works + test.RunBasicScenario_Load(); + + // Validates calling via reflection works + test.RunReflectionScenario_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 LoadPairScalarVector64_Int32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray1; + private byte[] outArray2; + + private GCHandle inHandle1; + private GCHandle outHandle1; + private GCHandle outHandle2; + + private ulong alignment; + + public DataTable(Int32[] inArray1, Int32[] outArray1, Int32[] outArray2, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray1 = outArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray2 = outArray2.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 32) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray1 || (alignment * 2) < sizeOfoutArray2) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray1 = new byte[alignment * 2]; + this.outArray2 = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle1 = GCHandle.Alloc(this.outArray1, GCHandleType.Pinned); + this.outHandle2 = GCHandle.Alloc(this.outArray2, 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* outArray1Ptr => Align((byte*)(outHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArray2Ptr => Align((byte*)(outHandle2.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle1.Free(); + outHandle2.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Ret1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int Ret2ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int Op1ElementCount = Ret1ElementCount + Ret2ElementCount; + + private static Int32[] _data = new Int32[Op1ElementCount]; + + private DataTable _dataTable; + + public LoadPairScalarVector64_Int32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data, new Int32[Ret1ElementCount], new Int32[Ret2ElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var (value1, value2) = AdvSimd.Arm64.LoadPairScalarVector64((Int32*)(_dataTable.inArray1Ptr)); + Unsafe.Write(_dataTable.outArray1Ptr, value1); + Unsafe.Write(_dataTable.outArray2Ptr, value2); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArray1Ptr, _dataTable.outArray2Ptr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.LoadPairScalarVector64), new Type[] { typeof(Int32*) }) + .Invoke(null, new object[] { + Pointer.Box(_dataTable.inArray1Ptr, typeof(Int32*)) + }); + + var (value1, value2) = ((Vector64, Vector64))result; + + Unsafe.Write(_dataTable.outArray1Ptr, value1); + Unsafe.Write(_dataTable.outArray2Ptr, value2); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArray1Ptr, _dataTable.outArray2Ptr); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + Succeeded = false; + + try + { + RunBasicScenario_Load(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(void* firstOp, void* result1, void* result2, [CallerMemberName] string method = "") + { + Int32[] inArray = new Int32[Op1ElementCount]; + Int32[] outArray1 = new Int32[Ret1ElementCount]; + Int32[] outArray2 = new Int32[Ret2ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)(Unsafe.SizeOf() * Op1ElementCount)); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray1[0]), ref Unsafe.AsRef(result1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray2[0]), ref Unsafe.AsRef(result2), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray1, outArray2, method); + } + + private void ValidateResult(Int32[] firstOp, Int32[] firstResult, Int32[] secondResult, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (int i = 0; i < Op1ElementCount; i++) + { + if (Helpers.Take(firstOp, 2, i) != Helpers.ConcatScalar(firstResult, secondResult, i)) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.LoadPairScalarVector64)}(Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" firstResult: ({string.Join(", ", firstResult)})"); + TestLibrary.TestFramework.LogInformation($"secondResult: ({string.Join(", ", secondResult)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairScalarVector64.Single.cs b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairScalarVector64.Single.cs new file mode 100644 index 00000000000000..90bf91fe4ddc8a --- /dev/null +++ b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairScalarVector64.Single.cs @@ -0,0 +1,203 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Reflection; +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 LoadPairScalarVector64_Single() + { + var test = new LoadPairScalarVector64_Single(); + + if (test.IsSupported) + { + // Validates basic functionality works + test.RunBasicScenario_Load(); + + // Validates calling via reflection works + test.RunReflectionScenario_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 LoadPairScalarVector64_Single + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray1; + private byte[] outArray2; + + private GCHandle inHandle1; + private GCHandle outHandle1; + private GCHandle outHandle2; + + private ulong alignment; + + public DataTable(Single[] inArray1, Single[] outArray1, Single[] outArray2, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray1 = outArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray2 = outArray2.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 32) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray1 || (alignment * 2) < sizeOfoutArray2) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray1 = new byte[alignment * 2]; + this.outArray2 = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle1 = GCHandle.Alloc(this.outArray1, GCHandleType.Pinned); + this.outHandle2 = GCHandle.Alloc(this.outArray2, 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* outArray1Ptr => Align((byte*)(outHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArray2Ptr => Align((byte*)(outHandle2.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle1.Free(); + outHandle2.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Ret1ElementCount = Unsafe.SizeOf>() / sizeof(Single); + private static readonly int Ret2ElementCount = Unsafe.SizeOf>() / sizeof(Single); + private static readonly int Op1ElementCount = Ret1ElementCount + Ret2ElementCount; + + private static Single[] _data = new Single[Op1ElementCount]; + + private DataTable _dataTable; + + public LoadPairScalarVector64_Single() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetSingle(); } + _dataTable = new DataTable(_data, new Single[Ret1ElementCount], new Single[Ret2ElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var (value1, value2) = AdvSimd.Arm64.LoadPairScalarVector64((Single*)(_dataTable.inArray1Ptr)); + Unsafe.Write(_dataTable.outArray1Ptr, value1); + Unsafe.Write(_dataTable.outArray2Ptr, value2); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArray1Ptr, _dataTable.outArray2Ptr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.LoadPairScalarVector64), new Type[] { typeof(Single*) }) + .Invoke(null, new object[] { + Pointer.Box(_dataTable.inArray1Ptr, typeof(Single*)) + }); + + var (value1, value2) = ((Vector64, Vector64))result; + + Unsafe.Write(_dataTable.outArray1Ptr, value1); + Unsafe.Write(_dataTable.outArray2Ptr, value2); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArray1Ptr, _dataTable.outArray2Ptr); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + Succeeded = false; + + try + { + RunBasicScenario_Load(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(void* firstOp, void* result1, void* result2, [CallerMemberName] string method = "") + { + Single[] inArray = new Single[Op1ElementCount]; + Single[] outArray1 = new Single[Ret1ElementCount]; + Single[] outArray2 = new Single[Ret2ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)(Unsafe.SizeOf() * Op1ElementCount)); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray1[0]), ref Unsafe.AsRef(result1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray2[0]), ref Unsafe.AsRef(result2), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray1, outArray2, method); + } + + private void ValidateResult(Single[] firstOp, Single[] firstResult, Single[] secondResult, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (int i = 0; i < Op1ElementCount; i++) + { + if (BitConverter.SingleToInt32Bits(Helpers.Take(firstOp, 2, i)) != BitConverter.SingleToInt32Bits(Helpers.ConcatScalar(firstResult, secondResult, i))) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.LoadPairScalarVector64)}(Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" firstResult: ({string.Join(", ", firstResult)})"); + TestLibrary.TestFramework.LogInformation($"secondResult: ({string.Join(", ", secondResult)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairScalarVector64.UInt32.cs b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairScalarVector64.UInt32.cs new file mode 100644 index 00000000000000..fa9cf749dd6ed5 --- /dev/null +++ b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairScalarVector64.UInt32.cs @@ -0,0 +1,203 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Reflection; +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 LoadPairScalarVector64_UInt32() + { + var test = new LoadPairScalarVector64_UInt32(); + + if (test.IsSupported) + { + // Validates basic functionality works + test.RunBasicScenario_Load(); + + // Validates calling via reflection works + test.RunReflectionScenario_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 LoadPairScalarVector64_UInt32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray1; + private byte[] outArray2; + + private GCHandle inHandle1; + private GCHandle outHandle1; + private GCHandle outHandle2; + + private ulong alignment; + + public DataTable(UInt32[] inArray1, UInt32[] outArray1, UInt32[] outArray2, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray1 = outArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray2 = outArray2.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 32) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray1 || (alignment * 2) < sizeOfoutArray2) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray1 = new byte[alignment * 2]; + this.outArray2 = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle1 = GCHandle.Alloc(this.outArray1, GCHandleType.Pinned); + this.outHandle2 = GCHandle.Alloc(this.outArray2, 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* outArray1Ptr => Align((byte*)(outHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArray2Ptr => Align((byte*)(outHandle2.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle1.Free(); + outHandle2.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Ret1ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int Ret2ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int Op1ElementCount = Ret1ElementCount + Ret2ElementCount; + + private static UInt32[] _data = new UInt32[Op1ElementCount]; + + private DataTable _dataTable; + + public LoadPairScalarVector64_UInt32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt32(); } + _dataTable = new DataTable(_data, new UInt32[Ret1ElementCount], new UInt32[Ret2ElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var (value1, value2) = AdvSimd.Arm64.LoadPairScalarVector64((UInt32*)(_dataTable.inArray1Ptr)); + Unsafe.Write(_dataTable.outArray1Ptr, value1); + Unsafe.Write(_dataTable.outArray2Ptr, value2); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArray1Ptr, _dataTable.outArray2Ptr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.LoadPairScalarVector64), new Type[] { typeof(UInt32*) }) + .Invoke(null, new object[] { + Pointer.Box(_dataTable.inArray1Ptr, typeof(UInt32*)) + }); + + var (value1, value2) = ((Vector64, Vector64))result; + + Unsafe.Write(_dataTable.outArray1Ptr, value1); + Unsafe.Write(_dataTable.outArray2Ptr, value2); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArray1Ptr, _dataTable.outArray2Ptr); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + Succeeded = false; + + try + { + RunBasicScenario_Load(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(void* firstOp, void* result1, void* result2, [CallerMemberName] string method = "") + { + UInt32[] inArray = new UInt32[Op1ElementCount]; + UInt32[] outArray1 = new UInt32[Ret1ElementCount]; + UInt32[] outArray2 = new UInt32[Ret2ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)(Unsafe.SizeOf() * Op1ElementCount)); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray1[0]), ref Unsafe.AsRef(result1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray2[0]), ref Unsafe.AsRef(result2), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray1, outArray2, method); + } + + private void ValidateResult(UInt32[] firstOp, UInt32[] firstResult, UInt32[] secondResult, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (int i = 0; i < Op1ElementCount; i++) + { + if (Helpers.Take(firstOp, 2, i) != Helpers.ConcatScalar(firstResult, secondResult, i)) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.LoadPairScalarVector64)}(Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" firstResult: ({string.Join(", ", firstResult)})"); + TestLibrary.TestFramework.LogInformation($"secondResult: ({string.Join(", ", secondResult)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairScalarVector64NonTemporal.Int32.cs b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairScalarVector64NonTemporal.Int32.cs new file mode 100644 index 00000000000000..11c14ce76faa86 --- /dev/null +++ b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairScalarVector64NonTemporal.Int32.cs @@ -0,0 +1,203 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Reflection; +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 LoadPairScalarVector64NonTemporal_Int32() + { + var test = new LoadPairScalarVector64NonTemporal_Int32(); + + if (test.IsSupported) + { + // Validates basic functionality works + test.RunBasicScenario_Load(); + + // Validates calling via reflection works + test.RunReflectionScenario_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 LoadPairScalarVector64NonTemporal_Int32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray1; + private byte[] outArray2; + + private GCHandle inHandle1; + private GCHandle outHandle1; + private GCHandle outHandle2; + + private ulong alignment; + + public DataTable(Int32[] inArray1, Int32[] outArray1, Int32[] outArray2, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray1 = outArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray2 = outArray2.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 32) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray1 || (alignment * 2) < sizeOfoutArray2) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray1 = new byte[alignment * 2]; + this.outArray2 = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle1 = GCHandle.Alloc(this.outArray1, GCHandleType.Pinned); + this.outHandle2 = GCHandle.Alloc(this.outArray2, 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* outArray1Ptr => Align((byte*)(outHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArray2Ptr => Align((byte*)(outHandle2.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle1.Free(); + outHandle2.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Ret1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int Ret2ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int Op1ElementCount = Ret1ElementCount + Ret2ElementCount; + + private static Int32[] _data = new Int32[Op1ElementCount]; + + private DataTable _dataTable; + + public LoadPairScalarVector64NonTemporal_Int32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data, new Int32[Ret1ElementCount], new Int32[Ret2ElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var (value1, value2) = AdvSimd.Arm64.LoadPairScalarVector64NonTemporal((Int32*)(_dataTable.inArray1Ptr)); + Unsafe.Write(_dataTable.outArray1Ptr, value1); + Unsafe.Write(_dataTable.outArray2Ptr, value2); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArray1Ptr, _dataTable.outArray2Ptr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.LoadPairScalarVector64NonTemporal), new Type[] { typeof(Int32*) }) + .Invoke(null, new object[] { + Pointer.Box(_dataTable.inArray1Ptr, typeof(Int32*)) + }); + + var (value1, value2) = ((Vector64, Vector64))result; + + Unsafe.Write(_dataTable.outArray1Ptr, value1); + Unsafe.Write(_dataTable.outArray2Ptr, value2); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArray1Ptr, _dataTable.outArray2Ptr); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + Succeeded = false; + + try + { + RunBasicScenario_Load(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(void* firstOp, void* result1, void* result2, [CallerMemberName] string method = "") + { + Int32[] inArray = new Int32[Op1ElementCount]; + Int32[] outArray1 = new Int32[Ret1ElementCount]; + Int32[] outArray2 = new Int32[Ret2ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)(Unsafe.SizeOf() * Op1ElementCount)); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray1[0]), ref Unsafe.AsRef(result1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray2[0]), ref Unsafe.AsRef(result2), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray1, outArray2, method); + } + + private void ValidateResult(Int32[] firstOp, Int32[] firstResult, Int32[] secondResult, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (int i = 0; i < Op1ElementCount; i++) + { + if (Helpers.Take(firstOp, 2, i) != Helpers.ConcatScalar(firstResult, secondResult, i)) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.LoadPairScalarVector64NonTemporal)}(Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" firstResult: ({string.Join(", ", firstResult)})"); + TestLibrary.TestFramework.LogInformation($"secondResult: ({string.Join(", ", secondResult)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairScalarVector64NonTemporal.Single.cs b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairScalarVector64NonTemporal.Single.cs new file mode 100644 index 00000000000000..745b6675927c6c --- /dev/null +++ b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairScalarVector64NonTemporal.Single.cs @@ -0,0 +1,203 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Reflection; +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 LoadPairScalarVector64NonTemporal_Single() + { + var test = new LoadPairScalarVector64NonTemporal_Single(); + + if (test.IsSupported) + { + // Validates basic functionality works + test.RunBasicScenario_Load(); + + // Validates calling via reflection works + test.RunReflectionScenario_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 LoadPairScalarVector64NonTemporal_Single + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray1; + private byte[] outArray2; + + private GCHandle inHandle1; + private GCHandle outHandle1; + private GCHandle outHandle2; + + private ulong alignment; + + public DataTable(Single[] inArray1, Single[] outArray1, Single[] outArray2, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray1 = outArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray2 = outArray2.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 32) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray1 || (alignment * 2) < sizeOfoutArray2) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray1 = new byte[alignment * 2]; + this.outArray2 = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle1 = GCHandle.Alloc(this.outArray1, GCHandleType.Pinned); + this.outHandle2 = GCHandle.Alloc(this.outArray2, 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* outArray1Ptr => Align((byte*)(outHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArray2Ptr => Align((byte*)(outHandle2.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle1.Free(); + outHandle2.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Ret1ElementCount = Unsafe.SizeOf>() / sizeof(Single); + private static readonly int Ret2ElementCount = Unsafe.SizeOf>() / sizeof(Single); + private static readonly int Op1ElementCount = Ret1ElementCount + Ret2ElementCount; + + private static Single[] _data = new Single[Op1ElementCount]; + + private DataTable _dataTable; + + public LoadPairScalarVector64NonTemporal_Single() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetSingle(); } + _dataTable = new DataTable(_data, new Single[Ret1ElementCount], new Single[Ret2ElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var (value1, value2) = AdvSimd.Arm64.LoadPairScalarVector64NonTemporal((Single*)(_dataTable.inArray1Ptr)); + Unsafe.Write(_dataTable.outArray1Ptr, value1); + Unsafe.Write(_dataTable.outArray2Ptr, value2); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArray1Ptr, _dataTable.outArray2Ptr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.LoadPairScalarVector64NonTemporal), new Type[] { typeof(Single*) }) + .Invoke(null, new object[] { + Pointer.Box(_dataTable.inArray1Ptr, typeof(Single*)) + }); + + var (value1, value2) = ((Vector64, Vector64))result; + + Unsafe.Write(_dataTable.outArray1Ptr, value1); + Unsafe.Write(_dataTable.outArray2Ptr, value2); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArray1Ptr, _dataTable.outArray2Ptr); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + Succeeded = false; + + try + { + RunBasicScenario_Load(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(void* firstOp, void* result1, void* result2, [CallerMemberName] string method = "") + { + Single[] inArray = new Single[Op1ElementCount]; + Single[] outArray1 = new Single[Ret1ElementCount]; + Single[] outArray2 = new Single[Ret2ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)(Unsafe.SizeOf() * Op1ElementCount)); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray1[0]), ref Unsafe.AsRef(result1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray2[0]), ref Unsafe.AsRef(result2), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray1, outArray2, method); + } + + private void ValidateResult(Single[] firstOp, Single[] firstResult, Single[] secondResult, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (int i = 0; i < Op1ElementCount; i++) + { + if (BitConverter.SingleToInt32Bits(Helpers.Take(firstOp, 2, i)) != BitConverter.SingleToInt32Bits(Helpers.ConcatScalar(firstResult, secondResult, i))) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.LoadPairScalarVector64NonTemporal)}(Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" firstResult: ({string.Join(", ", firstResult)})"); + TestLibrary.TestFramework.LogInformation($"secondResult: ({string.Join(", ", secondResult)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairScalarVector64NonTemporal.UInt32.cs b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairScalarVector64NonTemporal.UInt32.cs new file mode 100644 index 00000000000000..8b25a5b640021e --- /dev/null +++ b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairScalarVector64NonTemporal.UInt32.cs @@ -0,0 +1,203 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Reflection; +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 LoadPairScalarVector64NonTemporal_UInt32() + { + var test = new LoadPairScalarVector64NonTemporal_UInt32(); + + if (test.IsSupported) + { + // Validates basic functionality works + test.RunBasicScenario_Load(); + + // Validates calling via reflection works + test.RunReflectionScenario_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 LoadPairScalarVector64NonTemporal_UInt32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray1; + private byte[] outArray2; + + private GCHandle inHandle1; + private GCHandle outHandle1; + private GCHandle outHandle2; + + private ulong alignment; + + public DataTable(UInt32[] inArray1, UInt32[] outArray1, UInt32[] outArray2, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray1 = outArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray2 = outArray2.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 32) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray1 || (alignment * 2) < sizeOfoutArray2) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray1 = new byte[alignment * 2]; + this.outArray2 = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle1 = GCHandle.Alloc(this.outArray1, GCHandleType.Pinned); + this.outHandle2 = GCHandle.Alloc(this.outArray2, 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* outArray1Ptr => Align((byte*)(outHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArray2Ptr => Align((byte*)(outHandle2.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle1.Free(); + outHandle2.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Ret1ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int Ret2ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int Op1ElementCount = Ret1ElementCount + Ret2ElementCount; + + private static UInt32[] _data = new UInt32[Op1ElementCount]; + + private DataTable _dataTable; + + public LoadPairScalarVector64NonTemporal_UInt32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt32(); } + _dataTable = new DataTable(_data, new UInt32[Ret1ElementCount], new UInt32[Ret2ElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var (value1, value2) = AdvSimd.Arm64.LoadPairScalarVector64NonTemporal((UInt32*)(_dataTable.inArray1Ptr)); + Unsafe.Write(_dataTable.outArray1Ptr, value1); + Unsafe.Write(_dataTable.outArray2Ptr, value2); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArray1Ptr, _dataTable.outArray2Ptr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.LoadPairScalarVector64NonTemporal), new Type[] { typeof(UInt32*) }) + .Invoke(null, new object[] { + Pointer.Box(_dataTable.inArray1Ptr, typeof(UInt32*)) + }); + + var (value1, value2) = ((Vector64, Vector64))result; + + Unsafe.Write(_dataTable.outArray1Ptr, value1); + Unsafe.Write(_dataTable.outArray2Ptr, value2); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArray1Ptr, _dataTable.outArray2Ptr); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + Succeeded = false; + + try + { + RunBasicScenario_Load(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(void* firstOp, void* result1, void* result2, [CallerMemberName] string method = "") + { + UInt32[] inArray = new UInt32[Op1ElementCount]; + UInt32[] outArray1 = new UInt32[Ret1ElementCount]; + UInt32[] outArray2 = new UInt32[Ret2ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)(Unsafe.SizeOf() * Op1ElementCount)); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray1[0]), ref Unsafe.AsRef(result1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray2[0]), ref Unsafe.AsRef(result2), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray1, outArray2, method); + } + + private void ValidateResult(UInt32[] firstOp, UInt32[] firstResult, UInt32[] secondResult, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (int i = 0; i < Op1ElementCount; i++) + { + if (Helpers.Take(firstOp, 2, i) != Helpers.ConcatScalar(firstResult, secondResult, i)) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.LoadPairScalarVector64NonTemporal)}(Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" firstResult: ({string.Join(", ", firstResult)})"); + TestLibrary.TestFramework.LogInformation($"secondResult: ({string.Join(", ", secondResult)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector128.Byte.cs b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector128.Byte.cs new file mode 100644 index 00000000000000..e496bf3b68133d --- /dev/null +++ b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector128.Byte.cs @@ -0,0 +1,203 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Reflection; +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 LoadPairVector128_Byte() + { + var test = new LoadPairVector128_Byte(); + + if (test.IsSupported) + { + // Validates basic functionality works + test.RunBasicScenario_Load(); + + // Validates calling via reflection works + test.RunReflectionScenario_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 LoadPairVector128_Byte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray1; + private byte[] outArray2; + + private GCHandle inHandle1; + private GCHandle outHandle1; + private GCHandle outHandle2; + + private ulong alignment; + + public DataTable(Byte[] inArray1, Byte[] outArray1, Byte[] outArray2, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray1 = outArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray2 = outArray2.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 32) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray1 || (alignment * 2) < sizeOfoutArray2) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray1 = new byte[alignment * 2]; + this.outArray2 = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle1 = GCHandle.Alloc(this.outArray1, GCHandleType.Pinned); + this.outHandle2 = GCHandle.Alloc(this.outArray2, 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* outArray1Ptr => Align((byte*)(outHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArray2Ptr => Align((byte*)(outHandle2.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle1.Free(); + outHandle2.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private static readonly int LargestVectorSize = 32; + + private static readonly int Ret1ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int Ret2ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int Op1ElementCount = Ret1ElementCount + Ret2ElementCount; + + private static Byte[] _data = new Byte[Op1ElementCount]; + + private DataTable _dataTable; + + public LoadPairVector128_Byte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetByte(); } + _dataTable = new DataTable(_data, new Byte[Ret1ElementCount], new Byte[Ret2ElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var (value1, value2) = AdvSimd.Arm64.LoadPairVector128((Byte*)(_dataTable.inArray1Ptr)); + Unsafe.Write(_dataTable.outArray1Ptr, value1); + Unsafe.Write(_dataTable.outArray2Ptr, value2); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArray1Ptr, _dataTable.outArray2Ptr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.LoadPairVector128), new Type[] { typeof(Byte*) }) + .Invoke(null, new object[] { + Pointer.Box(_dataTable.inArray1Ptr, typeof(Byte*)) + }); + + var (value1, value2) = ((Vector128, Vector128))result; + + Unsafe.Write(_dataTable.outArray1Ptr, value1); + Unsafe.Write(_dataTable.outArray2Ptr, value2); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArray1Ptr, _dataTable.outArray2Ptr); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + Succeeded = false; + + try + { + RunBasicScenario_Load(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(void* firstOp, void* result1, void* result2, [CallerMemberName] string method = "") + { + Byte[] inArray = new Byte[Op1ElementCount]; + Byte[] outArray1 = new Byte[Ret1ElementCount]; + Byte[] outArray2 = new Byte[Ret2ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)(Unsafe.SizeOf() * Op1ElementCount)); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray1[0]), ref Unsafe.AsRef(result1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray2[0]), ref Unsafe.AsRef(result2), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray1, outArray2, method); + } + + private void ValidateResult(Byte[] firstOp, Byte[] firstResult, Byte[] secondResult, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (int i = 0; i < Op1ElementCount; i++) + { + if (firstOp[i] != Helpers.Concat(firstResult, secondResult, i)) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.LoadPairVector128)}(Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" firstResult: ({string.Join(", ", firstResult)})"); + TestLibrary.TestFramework.LogInformation($"secondResult: ({string.Join(", ", secondResult)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector128.Double.cs b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector128.Double.cs new file mode 100644 index 00000000000000..62ed8ddffb8446 --- /dev/null +++ b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector128.Double.cs @@ -0,0 +1,203 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Reflection; +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 LoadPairVector128_Double() + { + var test = new LoadPairVector128_Double(); + + if (test.IsSupported) + { + // Validates basic functionality works + test.RunBasicScenario_Load(); + + // Validates calling via reflection works + test.RunReflectionScenario_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 LoadPairVector128_Double + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray1; + private byte[] outArray2; + + private GCHandle inHandle1; + private GCHandle outHandle1; + private GCHandle outHandle2; + + private ulong alignment; + + public DataTable(Double[] inArray1, Double[] outArray1, Double[] outArray2, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray1 = outArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray2 = outArray2.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 32) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray1 || (alignment * 2) < sizeOfoutArray2) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray1 = new byte[alignment * 2]; + this.outArray2 = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle1 = GCHandle.Alloc(this.outArray1, GCHandleType.Pinned); + this.outHandle2 = GCHandle.Alloc(this.outArray2, 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* outArray1Ptr => Align((byte*)(outHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArray2Ptr => Align((byte*)(outHandle2.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle1.Free(); + outHandle2.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private static readonly int LargestVectorSize = 32; + + private static readonly int Ret1ElementCount = Unsafe.SizeOf>() / sizeof(Double); + private static readonly int Ret2ElementCount = Unsafe.SizeOf>() / sizeof(Double); + private static readonly int Op1ElementCount = Ret1ElementCount + Ret2ElementCount; + + private static Double[] _data = new Double[Op1ElementCount]; + + private DataTable _dataTable; + + public LoadPairVector128_Double() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetDouble(); } + _dataTable = new DataTable(_data, new Double[Ret1ElementCount], new Double[Ret2ElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var (value1, value2) = AdvSimd.Arm64.LoadPairVector128((Double*)(_dataTable.inArray1Ptr)); + Unsafe.Write(_dataTable.outArray1Ptr, value1); + Unsafe.Write(_dataTable.outArray2Ptr, value2); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArray1Ptr, _dataTable.outArray2Ptr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.LoadPairVector128), new Type[] { typeof(Double*) }) + .Invoke(null, new object[] { + Pointer.Box(_dataTable.inArray1Ptr, typeof(Double*)) + }); + + var (value1, value2) = ((Vector128, Vector128))result; + + Unsafe.Write(_dataTable.outArray1Ptr, value1); + Unsafe.Write(_dataTable.outArray2Ptr, value2); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArray1Ptr, _dataTable.outArray2Ptr); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + Succeeded = false; + + try + { + RunBasicScenario_Load(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(void* firstOp, void* result1, void* result2, [CallerMemberName] string method = "") + { + Double[] inArray = new Double[Op1ElementCount]; + Double[] outArray1 = new Double[Ret1ElementCount]; + Double[] outArray2 = new Double[Ret2ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)(Unsafe.SizeOf() * Op1ElementCount)); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray1[0]), ref Unsafe.AsRef(result1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray2[0]), ref Unsafe.AsRef(result2), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray1, outArray2, method); + } + + private void ValidateResult(Double[] firstOp, Double[] firstResult, Double[] secondResult, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (int i = 0; i < Op1ElementCount; i++) + { + if (BitConverter.DoubleToInt64Bits(firstOp[i]) != BitConverter.DoubleToInt64Bits(Helpers.Concat(firstResult, secondResult, i))) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.LoadPairVector128)}(Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" firstResult: ({string.Join(", ", firstResult)})"); + TestLibrary.TestFramework.LogInformation($"secondResult: ({string.Join(", ", secondResult)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector128.Int16.cs b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector128.Int16.cs new file mode 100644 index 00000000000000..6bb7e8123a0621 --- /dev/null +++ b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector128.Int16.cs @@ -0,0 +1,203 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Reflection; +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 LoadPairVector128_Int16() + { + var test = new LoadPairVector128_Int16(); + + if (test.IsSupported) + { + // Validates basic functionality works + test.RunBasicScenario_Load(); + + // Validates calling via reflection works + test.RunReflectionScenario_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 LoadPairVector128_Int16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray1; + private byte[] outArray2; + + private GCHandle inHandle1; + private GCHandle outHandle1; + private GCHandle outHandle2; + + private ulong alignment; + + public DataTable(Int16[] inArray1, Int16[] outArray1, Int16[] outArray2, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray1 = outArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray2 = outArray2.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 32) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray1 || (alignment * 2) < sizeOfoutArray2) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray1 = new byte[alignment * 2]; + this.outArray2 = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle1 = GCHandle.Alloc(this.outArray1, GCHandleType.Pinned); + this.outHandle2 = GCHandle.Alloc(this.outArray2, 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* outArray1Ptr => Align((byte*)(outHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArray2Ptr => Align((byte*)(outHandle2.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle1.Free(); + outHandle2.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private static readonly int LargestVectorSize = 32; + + private static readonly int Ret1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int Ret2ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int Op1ElementCount = Ret1ElementCount + Ret2ElementCount; + + private static Int16[] _data = new Int16[Op1ElementCount]; + + private DataTable _dataTable; + + public LoadPairVector128_Int16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data, new Int16[Ret1ElementCount], new Int16[Ret2ElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var (value1, value2) = AdvSimd.Arm64.LoadPairVector128((Int16*)(_dataTable.inArray1Ptr)); + Unsafe.Write(_dataTable.outArray1Ptr, value1); + Unsafe.Write(_dataTable.outArray2Ptr, value2); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArray1Ptr, _dataTable.outArray2Ptr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.LoadPairVector128), new Type[] { typeof(Int16*) }) + .Invoke(null, new object[] { + Pointer.Box(_dataTable.inArray1Ptr, typeof(Int16*)) + }); + + var (value1, value2) = ((Vector128, Vector128))result; + + Unsafe.Write(_dataTable.outArray1Ptr, value1); + Unsafe.Write(_dataTable.outArray2Ptr, value2); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArray1Ptr, _dataTable.outArray2Ptr); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + Succeeded = false; + + try + { + RunBasicScenario_Load(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(void* firstOp, void* result1, void* result2, [CallerMemberName] string method = "") + { + Int16[] inArray = new Int16[Op1ElementCount]; + Int16[] outArray1 = new Int16[Ret1ElementCount]; + Int16[] outArray2 = new Int16[Ret2ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)(Unsafe.SizeOf() * Op1ElementCount)); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray1[0]), ref Unsafe.AsRef(result1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray2[0]), ref Unsafe.AsRef(result2), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray1, outArray2, method); + } + + private void ValidateResult(Int16[] firstOp, Int16[] firstResult, Int16[] secondResult, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (int i = 0; i < Op1ElementCount; i++) + { + if (firstOp[i] != Helpers.Concat(firstResult, secondResult, i)) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.LoadPairVector128)}(Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" firstResult: ({string.Join(", ", firstResult)})"); + TestLibrary.TestFramework.LogInformation($"secondResult: ({string.Join(", ", secondResult)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector128.Int32.cs b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector128.Int32.cs new file mode 100644 index 00000000000000..93db8b9dadc246 --- /dev/null +++ b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector128.Int32.cs @@ -0,0 +1,203 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Reflection; +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 LoadPairVector128_Int32() + { + var test = new LoadPairVector128_Int32(); + + if (test.IsSupported) + { + // Validates basic functionality works + test.RunBasicScenario_Load(); + + // Validates calling via reflection works + test.RunReflectionScenario_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 LoadPairVector128_Int32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray1; + private byte[] outArray2; + + private GCHandle inHandle1; + private GCHandle outHandle1; + private GCHandle outHandle2; + + private ulong alignment; + + public DataTable(Int32[] inArray1, Int32[] outArray1, Int32[] outArray2, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray1 = outArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray2 = outArray2.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 32) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray1 || (alignment * 2) < sizeOfoutArray2) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray1 = new byte[alignment * 2]; + this.outArray2 = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle1 = GCHandle.Alloc(this.outArray1, GCHandleType.Pinned); + this.outHandle2 = GCHandle.Alloc(this.outArray2, 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* outArray1Ptr => Align((byte*)(outHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArray2Ptr => Align((byte*)(outHandle2.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle1.Free(); + outHandle2.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private static readonly int LargestVectorSize = 32; + + private static readonly int Ret1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int Ret2ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int Op1ElementCount = Ret1ElementCount + Ret2ElementCount; + + private static Int32[] _data = new Int32[Op1ElementCount]; + + private DataTable _dataTable; + + public LoadPairVector128_Int32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data, new Int32[Ret1ElementCount], new Int32[Ret2ElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var (value1, value2) = AdvSimd.Arm64.LoadPairVector128((Int32*)(_dataTable.inArray1Ptr)); + Unsafe.Write(_dataTable.outArray1Ptr, value1); + Unsafe.Write(_dataTable.outArray2Ptr, value2); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArray1Ptr, _dataTable.outArray2Ptr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.LoadPairVector128), new Type[] { typeof(Int32*) }) + .Invoke(null, new object[] { + Pointer.Box(_dataTable.inArray1Ptr, typeof(Int32*)) + }); + + var (value1, value2) = ((Vector128, Vector128))result; + + Unsafe.Write(_dataTable.outArray1Ptr, value1); + Unsafe.Write(_dataTable.outArray2Ptr, value2); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArray1Ptr, _dataTable.outArray2Ptr); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + Succeeded = false; + + try + { + RunBasicScenario_Load(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(void* firstOp, void* result1, void* result2, [CallerMemberName] string method = "") + { + Int32[] inArray = new Int32[Op1ElementCount]; + Int32[] outArray1 = new Int32[Ret1ElementCount]; + Int32[] outArray2 = new Int32[Ret2ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)(Unsafe.SizeOf() * Op1ElementCount)); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray1[0]), ref Unsafe.AsRef(result1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray2[0]), ref Unsafe.AsRef(result2), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray1, outArray2, method); + } + + private void ValidateResult(Int32[] firstOp, Int32[] firstResult, Int32[] secondResult, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (int i = 0; i < Op1ElementCount; i++) + { + if (firstOp[i] != Helpers.Concat(firstResult, secondResult, i)) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.LoadPairVector128)}(Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" firstResult: ({string.Join(", ", firstResult)})"); + TestLibrary.TestFramework.LogInformation($"secondResult: ({string.Join(", ", secondResult)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector128.Int64.cs b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector128.Int64.cs new file mode 100644 index 00000000000000..63fa02ba4b9b4b --- /dev/null +++ b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector128.Int64.cs @@ -0,0 +1,203 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Reflection; +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 LoadPairVector128_Int64() + { + var test = new LoadPairVector128_Int64(); + + if (test.IsSupported) + { + // Validates basic functionality works + test.RunBasicScenario_Load(); + + // Validates calling via reflection works + test.RunReflectionScenario_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 LoadPairVector128_Int64 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray1; + private byte[] outArray2; + + private GCHandle inHandle1; + private GCHandle outHandle1; + private GCHandle outHandle2; + + private ulong alignment; + + public DataTable(Int64[] inArray1, Int64[] outArray1, Int64[] outArray2, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray1 = outArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray2 = outArray2.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 32) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray1 || (alignment * 2) < sizeOfoutArray2) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray1 = new byte[alignment * 2]; + this.outArray2 = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle1 = GCHandle.Alloc(this.outArray1, GCHandleType.Pinned); + this.outHandle2 = GCHandle.Alloc(this.outArray2, 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* outArray1Ptr => Align((byte*)(outHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArray2Ptr => Align((byte*)(outHandle2.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle1.Free(); + outHandle2.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private static readonly int LargestVectorSize = 32; + + private static readonly int Ret1ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int Ret2ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int Op1ElementCount = Ret1ElementCount + Ret2ElementCount; + + private static Int64[] _data = new Int64[Op1ElementCount]; + + private DataTable _dataTable; + + public LoadPairVector128_Int64() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + _dataTable = new DataTable(_data, new Int64[Ret1ElementCount], new Int64[Ret2ElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var (value1, value2) = AdvSimd.Arm64.LoadPairVector128((Int64*)(_dataTable.inArray1Ptr)); + Unsafe.Write(_dataTable.outArray1Ptr, value1); + Unsafe.Write(_dataTable.outArray2Ptr, value2); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArray1Ptr, _dataTable.outArray2Ptr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.LoadPairVector128), new Type[] { typeof(Int64*) }) + .Invoke(null, new object[] { + Pointer.Box(_dataTable.inArray1Ptr, typeof(Int64*)) + }); + + var (value1, value2) = ((Vector128, Vector128))result; + + Unsafe.Write(_dataTable.outArray1Ptr, value1); + Unsafe.Write(_dataTable.outArray2Ptr, value2); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArray1Ptr, _dataTable.outArray2Ptr); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + Succeeded = false; + + try + { + RunBasicScenario_Load(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(void* firstOp, void* result1, void* result2, [CallerMemberName] string method = "") + { + Int64[] inArray = new Int64[Op1ElementCount]; + Int64[] outArray1 = new Int64[Ret1ElementCount]; + Int64[] outArray2 = new Int64[Ret2ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)(Unsafe.SizeOf() * Op1ElementCount)); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray1[0]), ref Unsafe.AsRef(result1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray2[0]), ref Unsafe.AsRef(result2), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray1, outArray2, method); + } + + private void ValidateResult(Int64[] firstOp, Int64[] firstResult, Int64[] secondResult, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (int i = 0; i < Op1ElementCount; i++) + { + if (firstOp[i] != Helpers.Concat(firstResult, secondResult, i)) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.LoadPairVector128)}(Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" firstResult: ({string.Join(", ", firstResult)})"); + TestLibrary.TestFramework.LogInformation($"secondResult: ({string.Join(", ", secondResult)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector128.SByte.cs b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector128.SByte.cs new file mode 100644 index 00000000000000..60a659a033305f --- /dev/null +++ b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector128.SByte.cs @@ -0,0 +1,203 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Reflection; +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 LoadPairVector128_SByte() + { + var test = new LoadPairVector128_SByte(); + + if (test.IsSupported) + { + // Validates basic functionality works + test.RunBasicScenario_Load(); + + // Validates calling via reflection works + test.RunReflectionScenario_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 LoadPairVector128_SByte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray1; + private byte[] outArray2; + + private GCHandle inHandle1; + private GCHandle outHandle1; + private GCHandle outHandle2; + + private ulong alignment; + + public DataTable(SByte[] inArray1, SByte[] outArray1, SByte[] outArray2, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray1 = outArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray2 = outArray2.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 32) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray1 || (alignment * 2) < sizeOfoutArray2) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray1 = new byte[alignment * 2]; + this.outArray2 = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle1 = GCHandle.Alloc(this.outArray1, GCHandleType.Pinned); + this.outHandle2 = GCHandle.Alloc(this.outArray2, 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* outArray1Ptr => Align((byte*)(outHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArray2Ptr => Align((byte*)(outHandle2.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle1.Free(); + outHandle2.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private static readonly int LargestVectorSize = 32; + + private static readonly int Ret1ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int Ret2ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int Op1ElementCount = Ret1ElementCount + Ret2ElementCount; + + private static SByte[] _data = new SByte[Op1ElementCount]; + + private DataTable _dataTable; + + public LoadPairVector128_SByte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data, new SByte[Ret1ElementCount], new SByte[Ret2ElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var (value1, value2) = AdvSimd.Arm64.LoadPairVector128((SByte*)(_dataTable.inArray1Ptr)); + Unsafe.Write(_dataTable.outArray1Ptr, value1); + Unsafe.Write(_dataTable.outArray2Ptr, value2); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArray1Ptr, _dataTable.outArray2Ptr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.LoadPairVector128), new Type[] { typeof(SByte*) }) + .Invoke(null, new object[] { + Pointer.Box(_dataTable.inArray1Ptr, typeof(SByte*)) + }); + + var (value1, value2) = ((Vector128, Vector128))result; + + Unsafe.Write(_dataTable.outArray1Ptr, value1); + Unsafe.Write(_dataTable.outArray2Ptr, value2); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArray1Ptr, _dataTable.outArray2Ptr); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + Succeeded = false; + + try + { + RunBasicScenario_Load(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(void* firstOp, void* result1, void* result2, [CallerMemberName] string method = "") + { + SByte[] inArray = new SByte[Op1ElementCount]; + SByte[] outArray1 = new SByte[Ret1ElementCount]; + SByte[] outArray2 = new SByte[Ret2ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)(Unsafe.SizeOf() * Op1ElementCount)); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray1[0]), ref Unsafe.AsRef(result1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray2[0]), ref Unsafe.AsRef(result2), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray1, outArray2, method); + } + + private void ValidateResult(SByte[] firstOp, SByte[] firstResult, SByte[] secondResult, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (int i = 0; i < Op1ElementCount; i++) + { + if (firstOp[i] != Helpers.Concat(firstResult, secondResult, i)) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.LoadPairVector128)}(Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" firstResult: ({string.Join(", ", firstResult)})"); + TestLibrary.TestFramework.LogInformation($"secondResult: ({string.Join(", ", secondResult)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector128.Single.cs b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector128.Single.cs new file mode 100644 index 00000000000000..ba378b97b68496 --- /dev/null +++ b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector128.Single.cs @@ -0,0 +1,203 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Reflection; +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 LoadPairVector128_Single() + { + var test = new LoadPairVector128_Single(); + + if (test.IsSupported) + { + // Validates basic functionality works + test.RunBasicScenario_Load(); + + // Validates calling via reflection works + test.RunReflectionScenario_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 LoadPairVector128_Single + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray1; + private byte[] outArray2; + + private GCHandle inHandle1; + private GCHandle outHandle1; + private GCHandle outHandle2; + + private ulong alignment; + + public DataTable(Single[] inArray1, Single[] outArray1, Single[] outArray2, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray1 = outArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray2 = outArray2.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 32) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray1 || (alignment * 2) < sizeOfoutArray2) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray1 = new byte[alignment * 2]; + this.outArray2 = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle1 = GCHandle.Alloc(this.outArray1, GCHandleType.Pinned); + this.outHandle2 = GCHandle.Alloc(this.outArray2, 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* outArray1Ptr => Align((byte*)(outHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArray2Ptr => Align((byte*)(outHandle2.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle1.Free(); + outHandle2.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private static readonly int LargestVectorSize = 32; + + private static readonly int Ret1ElementCount = Unsafe.SizeOf>() / sizeof(Single); + private static readonly int Ret2ElementCount = Unsafe.SizeOf>() / sizeof(Single); + private static readonly int Op1ElementCount = Ret1ElementCount + Ret2ElementCount; + + private static Single[] _data = new Single[Op1ElementCount]; + + private DataTable _dataTable; + + public LoadPairVector128_Single() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetSingle(); } + _dataTable = new DataTable(_data, new Single[Ret1ElementCount], new Single[Ret2ElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var (value1, value2) = AdvSimd.Arm64.LoadPairVector128((Single*)(_dataTable.inArray1Ptr)); + Unsafe.Write(_dataTable.outArray1Ptr, value1); + Unsafe.Write(_dataTable.outArray2Ptr, value2); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArray1Ptr, _dataTable.outArray2Ptr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.LoadPairVector128), new Type[] { typeof(Single*) }) + .Invoke(null, new object[] { + Pointer.Box(_dataTable.inArray1Ptr, typeof(Single*)) + }); + + var (value1, value2) = ((Vector128, Vector128))result; + + Unsafe.Write(_dataTable.outArray1Ptr, value1); + Unsafe.Write(_dataTable.outArray2Ptr, value2); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArray1Ptr, _dataTable.outArray2Ptr); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + Succeeded = false; + + try + { + RunBasicScenario_Load(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(void* firstOp, void* result1, void* result2, [CallerMemberName] string method = "") + { + Single[] inArray = new Single[Op1ElementCount]; + Single[] outArray1 = new Single[Ret1ElementCount]; + Single[] outArray2 = new Single[Ret2ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)(Unsafe.SizeOf() * Op1ElementCount)); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray1[0]), ref Unsafe.AsRef(result1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray2[0]), ref Unsafe.AsRef(result2), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray1, outArray2, method); + } + + private void ValidateResult(Single[] firstOp, Single[] firstResult, Single[] secondResult, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (int i = 0; i < Op1ElementCount; i++) + { + if (BitConverter.SingleToInt32Bits(firstOp[i]) != BitConverter.SingleToInt32Bits(Helpers.Concat(firstResult, secondResult, i))) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.LoadPairVector128)}(Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" firstResult: ({string.Join(", ", firstResult)})"); + TestLibrary.TestFramework.LogInformation($"secondResult: ({string.Join(", ", secondResult)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector128.UInt16.cs b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector128.UInt16.cs new file mode 100644 index 00000000000000..8f8a183c0c6186 --- /dev/null +++ b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector128.UInt16.cs @@ -0,0 +1,203 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Reflection; +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 LoadPairVector128_UInt16() + { + var test = new LoadPairVector128_UInt16(); + + if (test.IsSupported) + { + // Validates basic functionality works + test.RunBasicScenario_Load(); + + // Validates calling via reflection works + test.RunReflectionScenario_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 LoadPairVector128_UInt16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray1; + private byte[] outArray2; + + private GCHandle inHandle1; + private GCHandle outHandle1; + private GCHandle outHandle2; + + private ulong alignment; + + public DataTable(UInt16[] inArray1, UInt16[] outArray1, UInt16[] outArray2, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray1 = outArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray2 = outArray2.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 32) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray1 || (alignment * 2) < sizeOfoutArray2) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray1 = new byte[alignment * 2]; + this.outArray2 = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle1 = GCHandle.Alloc(this.outArray1, GCHandleType.Pinned); + this.outHandle2 = GCHandle.Alloc(this.outArray2, 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* outArray1Ptr => Align((byte*)(outHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArray2Ptr => Align((byte*)(outHandle2.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle1.Free(); + outHandle2.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private static readonly int LargestVectorSize = 32; + + private static readonly int Ret1ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int Ret2ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int Op1ElementCount = Ret1ElementCount + Ret2ElementCount; + + private static UInt16[] _data = new UInt16[Op1ElementCount]; + + private DataTable _dataTable; + + public LoadPairVector128_UInt16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt16(); } + _dataTable = new DataTable(_data, new UInt16[Ret1ElementCount], new UInt16[Ret2ElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var (value1, value2) = AdvSimd.Arm64.LoadPairVector128((UInt16*)(_dataTable.inArray1Ptr)); + Unsafe.Write(_dataTable.outArray1Ptr, value1); + Unsafe.Write(_dataTable.outArray2Ptr, value2); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArray1Ptr, _dataTable.outArray2Ptr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.LoadPairVector128), new Type[] { typeof(UInt16*) }) + .Invoke(null, new object[] { + Pointer.Box(_dataTable.inArray1Ptr, typeof(UInt16*)) + }); + + var (value1, value2) = ((Vector128, Vector128))result; + + Unsafe.Write(_dataTable.outArray1Ptr, value1); + Unsafe.Write(_dataTable.outArray2Ptr, value2); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArray1Ptr, _dataTable.outArray2Ptr); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + Succeeded = false; + + try + { + RunBasicScenario_Load(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(void* firstOp, void* result1, void* result2, [CallerMemberName] string method = "") + { + UInt16[] inArray = new UInt16[Op1ElementCount]; + UInt16[] outArray1 = new UInt16[Ret1ElementCount]; + UInt16[] outArray2 = new UInt16[Ret2ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)(Unsafe.SizeOf() * Op1ElementCount)); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray1[0]), ref Unsafe.AsRef(result1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray2[0]), ref Unsafe.AsRef(result2), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray1, outArray2, method); + } + + private void ValidateResult(UInt16[] firstOp, UInt16[] firstResult, UInt16[] secondResult, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (int i = 0; i < Op1ElementCount; i++) + { + if (firstOp[i] != Helpers.Concat(firstResult, secondResult, i)) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.LoadPairVector128)}(Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" firstResult: ({string.Join(", ", firstResult)})"); + TestLibrary.TestFramework.LogInformation($"secondResult: ({string.Join(", ", secondResult)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector128.UInt32.cs b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector128.UInt32.cs new file mode 100644 index 00000000000000..3934ce7e3bf854 --- /dev/null +++ b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector128.UInt32.cs @@ -0,0 +1,203 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Reflection; +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 LoadPairVector128_UInt32() + { + var test = new LoadPairVector128_UInt32(); + + if (test.IsSupported) + { + // Validates basic functionality works + test.RunBasicScenario_Load(); + + // Validates calling via reflection works + test.RunReflectionScenario_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 LoadPairVector128_UInt32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray1; + private byte[] outArray2; + + private GCHandle inHandle1; + private GCHandle outHandle1; + private GCHandle outHandle2; + + private ulong alignment; + + public DataTable(UInt32[] inArray1, UInt32[] outArray1, UInt32[] outArray2, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray1 = outArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray2 = outArray2.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 32) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray1 || (alignment * 2) < sizeOfoutArray2) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray1 = new byte[alignment * 2]; + this.outArray2 = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle1 = GCHandle.Alloc(this.outArray1, GCHandleType.Pinned); + this.outHandle2 = GCHandle.Alloc(this.outArray2, 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* outArray1Ptr => Align((byte*)(outHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArray2Ptr => Align((byte*)(outHandle2.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle1.Free(); + outHandle2.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private static readonly int LargestVectorSize = 32; + + private static readonly int Ret1ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int Ret2ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int Op1ElementCount = Ret1ElementCount + Ret2ElementCount; + + private static UInt32[] _data = new UInt32[Op1ElementCount]; + + private DataTable _dataTable; + + public LoadPairVector128_UInt32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt32(); } + _dataTable = new DataTable(_data, new UInt32[Ret1ElementCount], new UInt32[Ret2ElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var (value1, value2) = AdvSimd.Arm64.LoadPairVector128((UInt32*)(_dataTable.inArray1Ptr)); + Unsafe.Write(_dataTable.outArray1Ptr, value1); + Unsafe.Write(_dataTable.outArray2Ptr, value2); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArray1Ptr, _dataTable.outArray2Ptr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.LoadPairVector128), new Type[] { typeof(UInt32*) }) + .Invoke(null, new object[] { + Pointer.Box(_dataTable.inArray1Ptr, typeof(UInt32*)) + }); + + var (value1, value2) = ((Vector128, Vector128))result; + + Unsafe.Write(_dataTable.outArray1Ptr, value1); + Unsafe.Write(_dataTable.outArray2Ptr, value2); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArray1Ptr, _dataTable.outArray2Ptr); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + Succeeded = false; + + try + { + RunBasicScenario_Load(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(void* firstOp, void* result1, void* result2, [CallerMemberName] string method = "") + { + UInt32[] inArray = new UInt32[Op1ElementCount]; + UInt32[] outArray1 = new UInt32[Ret1ElementCount]; + UInt32[] outArray2 = new UInt32[Ret2ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)(Unsafe.SizeOf() * Op1ElementCount)); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray1[0]), ref Unsafe.AsRef(result1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray2[0]), ref Unsafe.AsRef(result2), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray1, outArray2, method); + } + + private void ValidateResult(UInt32[] firstOp, UInt32[] firstResult, UInt32[] secondResult, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (int i = 0; i < Op1ElementCount; i++) + { + if (firstOp[i] != Helpers.Concat(firstResult, secondResult, i)) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.LoadPairVector128)}(Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" firstResult: ({string.Join(", ", firstResult)})"); + TestLibrary.TestFramework.LogInformation($"secondResult: ({string.Join(", ", secondResult)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector128.UInt64.cs b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector128.UInt64.cs new file mode 100644 index 00000000000000..c519d581c8761a --- /dev/null +++ b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector128.UInt64.cs @@ -0,0 +1,203 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Reflection; +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 LoadPairVector128_UInt64() + { + var test = new LoadPairVector128_UInt64(); + + if (test.IsSupported) + { + // Validates basic functionality works + test.RunBasicScenario_Load(); + + // Validates calling via reflection works + test.RunReflectionScenario_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 LoadPairVector128_UInt64 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray1; + private byte[] outArray2; + + private GCHandle inHandle1; + private GCHandle outHandle1; + private GCHandle outHandle2; + + private ulong alignment; + + public DataTable(UInt64[] inArray1, UInt64[] outArray1, UInt64[] outArray2, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray1 = outArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray2 = outArray2.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 32) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray1 || (alignment * 2) < sizeOfoutArray2) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray1 = new byte[alignment * 2]; + this.outArray2 = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle1 = GCHandle.Alloc(this.outArray1, GCHandleType.Pinned); + this.outHandle2 = GCHandle.Alloc(this.outArray2, 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* outArray1Ptr => Align((byte*)(outHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArray2Ptr => Align((byte*)(outHandle2.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle1.Free(); + outHandle2.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private static readonly int LargestVectorSize = 32; + + private static readonly int Ret1ElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + private static readonly int Ret2ElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + private static readonly int Op1ElementCount = Ret1ElementCount + Ret2ElementCount; + + private static UInt64[] _data = new UInt64[Op1ElementCount]; + + private DataTable _dataTable; + + public LoadPairVector128_UInt64() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt64(); } + _dataTable = new DataTable(_data, new UInt64[Ret1ElementCount], new UInt64[Ret2ElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var (value1, value2) = AdvSimd.Arm64.LoadPairVector128((UInt64*)(_dataTable.inArray1Ptr)); + Unsafe.Write(_dataTable.outArray1Ptr, value1); + Unsafe.Write(_dataTable.outArray2Ptr, value2); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArray1Ptr, _dataTable.outArray2Ptr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.LoadPairVector128), new Type[] { typeof(UInt64*) }) + .Invoke(null, new object[] { + Pointer.Box(_dataTable.inArray1Ptr, typeof(UInt64*)) + }); + + var (value1, value2) = ((Vector128, Vector128))result; + + Unsafe.Write(_dataTable.outArray1Ptr, value1); + Unsafe.Write(_dataTable.outArray2Ptr, value2); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArray1Ptr, _dataTable.outArray2Ptr); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + Succeeded = false; + + try + { + RunBasicScenario_Load(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(void* firstOp, void* result1, void* result2, [CallerMemberName] string method = "") + { + UInt64[] inArray = new UInt64[Op1ElementCount]; + UInt64[] outArray1 = new UInt64[Ret1ElementCount]; + UInt64[] outArray2 = new UInt64[Ret2ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)(Unsafe.SizeOf() * Op1ElementCount)); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray1[0]), ref Unsafe.AsRef(result1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray2[0]), ref Unsafe.AsRef(result2), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray1, outArray2, method); + } + + private void ValidateResult(UInt64[] firstOp, UInt64[] firstResult, UInt64[] secondResult, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (int i = 0; i < Op1ElementCount; i++) + { + if (firstOp[i] != Helpers.Concat(firstResult, secondResult, i)) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.LoadPairVector128)}(Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" firstResult: ({string.Join(", ", firstResult)})"); + TestLibrary.TestFramework.LogInformation($"secondResult: ({string.Join(", ", secondResult)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector128NonTemporal.Byte.cs b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector128NonTemporal.Byte.cs new file mode 100644 index 00000000000000..c173642887a70d --- /dev/null +++ b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector128NonTemporal.Byte.cs @@ -0,0 +1,203 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Reflection; +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 LoadPairVector128NonTemporal_Byte() + { + var test = new LoadPairVector128NonTemporal_Byte(); + + if (test.IsSupported) + { + // Validates basic functionality works + test.RunBasicScenario_Load(); + + // Validates calling via reflection works + test.RunReflectionScenario_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 LoadPairVector128NonTemporal_Byte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray1; + private byte[] outArray2; + + private GCHandle inHandle1; + private GCHandle outHandle1; + private GCHandle outHandle2; + + private ulong alignment; + + public DataTable(Byte[] inArray1, Byte[] outArray1, Byte[] outArray2, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray1 = outArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray2 = outArray2.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 32) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray1 || (alignment * 2) < sizeOfoutArray2) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray1 = new byte[alignment * 2]; + this.outArray2 = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle1 = GCHandle.Alloc(this.outArray1, GCHandleType.Pinned); + this.outHandle2 = GCHandle.Alloc(this.outArray2, 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* outArray1Ptr => Align((byte*)(outHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArray2Ptr => Align((byte*)(outHandle2.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle1.Free(); + outHandle2.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private static readonly int LargestVectorSize = 32; + + private static readonly int Ret1ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int Ret2ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int Op1ElementCount = Ret1ElementCount + Ret2ElementCount; + + private static Byte[] _data = new Byte[Op1ElementCount]; + + private DataTable _dataTable; + + public LoadPairVector128NonTemporal_Byte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetByte(); } + _dataTable = new DataTable(_data, new Byte[Ret1ElementCount], new Byte[Ret2ElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var (value1, value2) = AdvSimd.Arm64.LoadPairVector128NonTemporal((Byte*)(_dataTable.inArray1Ptr)); + Unsafe.Write(_dataTable.outArray1Ptr, value1); + Unsafe.Write(_dataTable.outArray2Ptr, value2); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArray1Ptr, _dataTable.outArray2Ptr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.LoadPairVector128NonTemporal), new Type[] { typeof(Byte*) }) + .Invoke(null, new object[] { + Pointer.Box(_dataTable.inArray1Ptr, typeof(Byte*)) + }); + + var (value1, value2) = ((Vector128, Vector128))result; + + Unsafe.Write(_dataTable.outArray1Ptr, value1); + Unsafe.Write(_dataTable.outArray2Ptr, value2); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArray1Ptr, _dataTable.outArray2Ptr); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + Succeeded = false; + + try + { + RunBasicScenario_Load(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(void* firstOp, void* result1, void* result2, [CallerMemberName] string method = "") + { + Byte[] inArray = new Byte[Op1ElementCount]; + Byte[] outArray1 = new Byte[Ret1ElementCount]; + Byte[] outArray2 = new Byte[Ret2ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)(Unsafe.SizeOf() * Op1ElementCount)); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray1[0]), ref Unsafe.AsRef(result1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray2[0]), ref Unsafe.AsRef(result2), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray1, outArray2, method); + } + + private void ValidateResult(Byte[] firstOp, Byte[] firstResult, Byte[] secondResult, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (int i = 0; i < Op1ElementCount; i++) + { + if (firstOp[i] != Helpers.Concat(firstResult, secondResult, i)) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.LoadPairVector128NonTemporal)}(Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" firstResult: ({string.Join(", ", firstResult)})"); + TestLibrary.TestFramework.LogInformation($"secondResult: ({string.Join(", ", secondResult)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector128NonTemporal.Double.cs b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector128NonTemporal.Double.cs new file mode 100644 index 00000000000000..84ad749eb09c1a --- /dev/null +++ b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector128NonTemporal.Double.cs @@ -0,0 +1,203 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Reflection; +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 LoadPairVector128NonTemporal_Double() + { + var test = new LoadPairVector128NonTemporal_Double(); + + if (test.IsSupported) + { + // Validates basic functionality works + test.RunBasicScenario_Load(); + + // Validates calling via reflection works + test.RunReflectionScenario_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 LoadPairVector128NonTemporal_Double + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray1; + private byte[] outArray2; + + private GCHandle inHandle1; + private GCHandle outHandle1; + private GCHandle outHandle2; + + private ulong alignment; + + public DataTable(Double[] inArray1, Double[] outArray1, Double[] outArray2, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray1 = outArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray2 = outArray2.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 32) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray1 || (alignment * 2) < sizeOfoutArray2) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray1 = new byte[alignment * 2]; + this.outArray2 = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle1 = GCHandle.Alloc(this.outArray1, GCHandleType.Pinned); + this.outHandle2 = GCHandle.Alloc(this.outArray2, 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* outArray1Ptr => Align((byte*)(outHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArray2Ptr => Align((byte*)(outHandle2.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle1.Free(); + outHandle2.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private static readonly int LargestVectorSize = 32; + + private static readonly int Ret1ElementCount = Unsafe.SizeOf>() / sizeof(Double); + private static readonly int Ret2ElementCount = Unsafe.SizeOf>() / sizeof(Double); + private static readonly int Op1ElementCount = Ret1ElementCount + Ret2ElementCount; + + private static Double[] _data = new Double[Op1ElementCount]; + + private DataTable _dataTable; + + public LoadPairVector128NonTemporal_Double() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetDouble(); } + _dataTable = new DataTable(_data, new Double[Ret1ElementCount], new Double[Ret2ElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var (value1, value2) = AdvSimd.Arm64.LoadPairVector128NonTemporal((Double*)(_dataTable.inArray1Ptr)); + Unsafe.Write(_dataTable.outArray1Ptr, value1); + Unsafe.Write(_dataTable.outArray2Ptr, value2); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArray1Ptr, _dataTable.outArray2Ptr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.LoadPairVector128NonTemporal), new Type[] { typeof(Double*) }) + .Invoke(null, new object[] { + Pointer.Box(_dataTable.inArray1Ptr, typeof(Double*)) + }); + + var (value1, value2) = ((Vector128, Vector128))result; + + Unsafe.Write(_dataTable.outArray1Ptr, value1); + Unsafe.Write(_dataTable.outArray2Ptr, value2); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArray1Ptr, _dataTable.outArray2Ptr); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + Succeeded = false; + + try + { + RunBasicScenario_Load(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(void* firstOp, void* result1, void* result2, [CallerMemberName] string method = "") + { + Double[] inArray = new Double[Op1ElementCount]; + Double[] outArray1 = new Double[Ret1ElementCount]; + Double[] outArray2 = new Double[Ret2ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)(Unsafe.SizeOf() * Op1ElementCount)); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray1[0]), ref Unsafe.AsRef(result1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray2[0]), ref Unsafe.AsRef(result2), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray1, outArray2, method); + } + + private void ValidateResult(Double[] firstOp, Double[] firstResult, Double[] secondResult, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (int i = 0; i < Op1ElementCount; i++) + { + if (BitConverter.DoubleToInt64Bits(firstOp[i]) != BitConverter.DoubleToInt64Bits(Helpers.Concat(firstResult, secondResult, i))) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.LoadPairVector128NonTemporal)}(Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" firstResult: ({string.Join(", ", firstResult)})"); + TestLibrary.TestFramework.LogInformation($"secondResult: ({string.Join(", ", secondResult)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector128NonTemporal.Int16.cs b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector128NonTemporal.Int16.cs new file mode 100644 index 00000000000000..12b6c1b95178cb --- /dev/null +++ b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector128NonTemporal.Int16.cs @@ -0,0 +1,203 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Reflection; +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 LoadPairVector128NonTemporal_Int16() + { + var test = new LoadPairVector128NonTemporal_Int16(); + + if (test.IsSupported) + { + // Validates basic functionality works + test.RunBasicScenario_Load(); + + // Validates calling via reflection works + test.RunReflectionScenario_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 LoadPairVector128NonTemporal_Int16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray1; + private byte[] outArray2; + + private GCHandle inHandle1; + private GCHandle outHandle1; + private GCHandle outHandle2; + + private ulong alignment; + + public DataTable(Int16[] inArray1, Int16[] outArray1, Int16[] outArray2, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray1 = outArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray2 = outArray2.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 32) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray1 || (alignment * 2) < sizeOfoutArray2) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray1 = new byte[alignment * 2]; + this.outArray2 = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle1 = GCHandle.Alloc(this.outArray1, GCHandleType.Pinned); + this.outHandle2 = GCHandle.Alloc(this.outArray2, 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* outArray1Ptr => Align((byte*)(outHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArray2Ptr => Align((byte*)(outHandle2.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle1.Free(); + outHandle2.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private static readonly int LargestVectorSize = 32; + + private static readonly int Ret1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int Ret2ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int Op1ElementCount = Ret1ElementCount + Ret2ElementCount; + + private static Int16[] _data = new Int16[Op1ElementCount]; + + private DataTable _dataTable; + + public LoadPairVector128NonTemporal_Int16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data, new Int16[Ret1ElementCount], new Int16[Ret2ElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var (value1, value2) = AdvSimd.Arm64.LoadPairVector128NonTemporal((Int16*)(_dataTable.inArray1Ptr)); + Unsafe.Write(_dataTable.outArray1Ptr, value1); + Unsafe.Write(_dataTable.outArray2Ptr, value2); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArray1Ptr, _dataTable.outArray2Ptr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.LoadPairVector128NonTemporal), new Type[] { typeof(Int16*) }) + .Invoke(null, new object[] { + Pointer.Box(_dataTable.inArray1Ptr, typeof(Int16*)) + }); + + var (value1, value2) = ((Vector128, Vector128))result; + + Unsafe.Write(_dataTable.outArray1Ptr, value1); + Unsafe.Write(_dataTable.outArray2Ptr, value2); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArray1Ptr, _dataTable.outArray2Ptr); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + Succeeded = false; + + try + { + RunBasicScenario_Load(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(void* firstOp, void* result1, void* result2, [CallerMemberName] string method = "") + { + Int16[] inArray = new Int16[Op1ElementCount]; + Int16[] outArray1 = new Int16[Ret1ElementCount]; + Int16[] outArray2 = new Int16[Ret2ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)(Unsafe.SizeOf() * Op1ElementCount)); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray1[0]), ref Unsafe.AsRef(result1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray2[0]), ref Unsafe.AsRef(result2), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray1, outArray2, method); + } + + private void ValidateResult(Int16[] firstOp, Int16[] firstResult, Int16[] secondResult, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (int i = 0; i < Op1ElementCount; i++) + { + if (firstOp[i] != Helpers.Concat(firstResult, secondResult, i)) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.LoadPairVector128NonTemporal)}(Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" firstResult: ({string.Join(", ", firstResult)})"); + TestLibrary.TestFramework.LogInformation($"secondResult: ({string.Join(", ", secondResult)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector128NonTemporal.Int32.cs b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector128NonTemporal.Int32.cs new file mode 100644 index 00000000000000..9c06ef4d1cd3f6 --- /dev/null +++ b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector128NonTemporal.Int32.cs @@ -0,0 +1,203 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Reflection; +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 LoadPairVector128NonTemporal_Int32() + { + var test = new LoadPairVector128NonTemporal_Int32(); + + if (test.IsSupported) + { + // Validates basic functionality works + test.RunBasicScenario_Load(); + + // Validates calling via reflection works + test.RunReflectionScenario_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 LoadPairVector128NonTemporal_Int32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray1; + private byte[] outArray2; + + private GCHandle inHandle1; + private GCHandle outHandle1; + private GCHandle outHandle2; + + private ulong alignment; + + public DataTable(Int32[] inArray1, Int32[] outArray1, Int32[] outArray2, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray1 = outArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray2 = outArray2.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 32) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray1 || (alignment * 2) < sizeOfoutArray2) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray1 = new byte[alignment * 2]; + this.outArray2 = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle1 = GCHandle.Alloc(this.outArray1, GCHandleType.Pinned); + this.outHandle2 = GCHandle.Alloc(this.outArray2, 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* outArray1Ptr => Align((byte*)(outHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArray2Ptr => Align((byte*)(outHandle2.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle1.Free(); + outHandle2.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private static readonly int LargestVectorSize = 32; + + private static readonly int Ret1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int Ret2ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int Op1ElementCount = Ret1ElementCount + Ret2ElementCount; + + private static Int32[] _data = new Int32[Op1ElementCount]; + + private DataTable _dataTable; + + public LoadPairVector128NonTemporal_Int32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data, new Int32[Ret1ElementCount], new Int32[Ret2ElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var (value1, value2) = AdvSimd.Arm64.LoadPairVector128NonTemporal((Int32*)(_dataTable.inArray1Ptr)); + Unsafe.Write(_dataTable.outArray1Ptr, value1); + Unsafe.Write(_dataTable.outArray2Ptr, value2); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArray1Ptr, _dataTable.outArray2Ptr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.LoadPairVector128NonTemporal), new Type[] { typeof(Int32*) }) + .Invoke(null, new object[] { + Pointer.Box(_dataTable.inArray1Ptr, typeof(Int32*)) + }); + + var (value1, value2) = ((Vector128, Vector128))result; + + Unsafe.Write(_dataTable.outArray1Ptr, value1); + Unsafe.Write(_dataTable.outArray2Ptr, value2); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArray1Ptr, _dataTable.outArray2Ptr); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + Succeeded = false; + + try + { + RunBasicScenario_Load(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(void* firstOp, void* result1, void* result2, [CallerMemberName] string method = "") + { + Int32[] inArray = new Int32[Op1ElementCount]; + Int32[] outArray1 = new Int32[Ret1ElementCount]; + Int32[] outArray2 = new Int32[Ret2ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)(Unsafe.SizeOf() * Op1ElementCount)); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray1[0]), ref Unsafe.AsRef(result1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray2[0]), ref Unsafe.AsRef(result2), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray1, outArray2, method); + } + + private void ValidateResult(Int32[] firstOp, Int32[] firstResult, Int32[] secondResult, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (int i = 0; i < Op1ElementCount; i++) + { + if (firstOp[i] != Helpers.Concat(firstResult, secondResult, i)) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.LoadPairVector128NonTemporal)}(Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" firstResult: ({string.Join(", ", firstResult)})"); + TestLibrary.TestFramework.LogInformation($"secondResult: ({string.Join(", ", secondResult)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector128NonTemporal.Int64.cs b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector128NonTemporal.Int64.cs new file mode 100644 index 00000000000000..b68eeaac0ff0a1 --- /dev/null +++ b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector128NonTemporal.Int64.cs @@ -0,0 +1,203 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Reflection; +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 LoadPairVector128NonTemporal_Int64() + { + var test = new LoadPairVector128NonTemporal_Int64(); + + if (test.IsSupported) + { + // Validates basic functionality works + test.RunBasicScenario_Load(); + + // Validates calling via reflection works + test.RunReflectionScenario_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 LoadPairVector128NonTemporal_Int64 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray1; + private byte[] outArray2; + + private GCHandle inHandle1; + private GCHandle outHandle1; + private GCHandle outHandle2; + + private ulong alignment; + + public DataTable(Int64[] inArray1, Int64[] outArray1, Int64[] outArray2, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray1 = outArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray2 = outArray2.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 32) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray1 || (alignment * 2) < sizeOfoutArray2) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray1 = new byte[alignment * 2]; + this.outArray2 = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle1 = GCHandle.Alloc(this.outArray1, GCHandleType.Pinned); + this.outHandle2 = GCHandle.Alloc(this.outArray2, 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* outArray1Ptr => Align((byte*)(outHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArray2Ptr => Align((byte*)(outHandle2.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle1.Free(); + outHandle2.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private static readonly int LargestVectorSize = 32; + + private static readonly int Ret1ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int Ret2ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int Op1ElementCount = Ret1ElementCount + Ret2ElementCount; + + private static Int64[] _data = new Int64[Op1ElementCount]; + + private DataTable _dataTable; + + public LoadPairVector128NonTemporal_Int64() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + _dataTable = new DataTable(_data, new Int64[Ret1ElementCount], new Int64[Ret2ElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var (value1, value2) = AdvSimd.Arm64.LoadPairVector128NonTemporal((Int64*)(_dataTable.inArray1Ptr)); + Unsafe.Write(_dataTable.outArray1Ptr, value1); + Unsafe.Write(_dataTable.outArray2Ptr, value2); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArray1Ptr, _dataTable.outArray2Ptr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.LoadPairVector128NonTemporal), new Type[] { typeof(Int64*) }) + .Invoke(null, new object[] { + Pointer.Box(_dataTable.inArray1Ptr, typeof(Int64*)) + }); + + var (value1, value2) = ((Vector128, Vector128))result; + + Unsafe.Write(_dataTable.outArray1Ptr, value1); + Unsafe.Write(_dataTable.outArray2Ptr, value2); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArray1Ptr, _dataTable.outArray2Ptr); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + Succeeded = false; + + try + { + RunBasicScenario_Load(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(void* firstOp, void* result1, void* result2, [CallerMemberName] string method = "") + { + Int64[] inArray = new Int64[Op1ElementCount]; + Int64[] outArray1 = new Int64[Ret1ElementCount]; + Int64[] outArray2 = new Int64[Ret2ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)(Unsafe.SizeOf() * Op1ElementCount)); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray1[0]), ref Unsafe.AsRef(result1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray2[0]), ref Unsafe.AsRef(result2), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray1, outArray2, method); + } + + private void ValidateResult(Int64[] firstOp, Int64[] firstResult, Int64[] secondResult, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (int i = 0; i < Op1ElementCount; i++) + { + if (firstOp[i] != Helpers.Concat(firstResult, secondResult, i)) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.LoadPairVector128NonTemporal)}(Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" firstResult: ({string.Join(", ", firstResult)})"); + TestLibrary.TestFramework.LogInformation($"secondResult: ({string.Join(", ", secondResult)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector128NonTemporal.SByte.cs b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector128NonTemporal.SByte.cs new file mode 100644 index 00000000000000..f4af83bf72b6c0 --- /dev/null +++ b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector128NonTemporal.SByte.cs @@ -0,0 +1,203 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Reflection; +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 LoadPairVector128NonTemporal_SByte() + { + var test = new LoadPairVector128NonTemporal_SByte(); + + if (test.IsSupported) + { + // Validates basic functionality works + test.RunBasicScenario_Load(); + + // Validates calling via reflection works + test.RunReflectionScenario_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 LoadPairVector128NonTemporal_SByte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray1; + private byte[] outArray2; + + private GCHandle inHandle1; + private GCHandle outHandle1; + private GCHandle outHandle2; + + private ulong alignment; + + public DataTable(SByte[] inArray1, SByte[] outArray1, SByte[] outArray2, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray1 = outArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray2 = outArray2.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 32) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray1 || (alignment * 2) < sizeOfoutArray2) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray1 = new byte[alignment * 2]; + this.outArray2 = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle1 = GCHandle.Alloc(this.outArray1, GCHandleType.Pinned); + this.outHandle2 = GCHandle.Alloc(this.outArray2, 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* outArray1Ptr => Align((byte*)(outHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArray2Ptr => Align((byte*)(outHandle2.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle1.Free(); + outHandle2.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private static readonly int LargestVectorSize = 32; + + private static readonly int Ret1ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int Ret2ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int Op1ElementCount = Ret1ElementCount + Ret2ElementCount; + + private static SByte[] _data = new SByte[Op1ElementCount]; + + private DataTable _dataTable; + + public LoadPairVector128NonTemporal_SByte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data, new SByte[Ret1ElementCount], new SByte[Ret2ElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var (value1, value2) = AdvSimd.Arm64.LoadPairVector128NonTemporal((SByte*)(_dataTable.inArray1Ptr)); + Unsafe.Write(_dataTable.outArray1Ptr, value1); + Unsafe.Write(_dataTable.outArray2Ptr, value2); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArray1Ptr, _dataTable.outArray2Ptr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.LoadPairVector128NonTemporal), new Type[] { typeof(SByte*) }) + .Invoke(null, new object[] { + Pointer.Box(_dataTable.inArray1Ptr, typeof(SByte*)) + }); + + var (value1, value2) = ((Vector128, Vector128))result; + + Unsafe.Write(_dataTable.outArray1Ptr, value1); + Unsafe.Write(_dataTable.outArray2Ptr, value2); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArray1Ptr, _dataTable.outArray2Ptr); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + Succeeded = false; + + try + { + RunBasicScenario_Load(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(void* firstOp, void* result1, void* result2, [CallerMemberName] string method = "") + { + SByte[] inArray = new SByte[Op1ElementCount]; + SByte[] outArray1 = new SByte[Ret1ElementCount]; + SByte[] outArray2 = new SByte[Ret2ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)(Unsafe.SizeOf() * Op1ElementCount)); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray1[0]), ref Unsafe.AsRef(result1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray2[0]), ref Unsafe.AsRef(result2), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray1, outArray2, method); + } + + private void ValidateResult(SByte[] firstOp, SByte[] firstResult, SByte[] secondResult, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (int i = 0; i < Op1ElementCount; i++) + { + if (firstOp[i] != Helpers.Concat(firstResult, secondResult, i)) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.LoadPairVector128NonTemporal)}(Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" firstResult: ({string.Join(", ", firstResult)})"); + TestLibrary.TestFramework.LogInformation($"secondResult: ({string.Join(", ", secondResult)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector128NonTemporal.Single.cs b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector128NonTemporal.Single.cs new file mode 100644 index 00000000000000..b0c8be47a86907 --- /dev/null +++ b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector128NonTemporal.Single.cs @@ -0,0 +1,203 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Reflection; +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 LoadPairVector128NonTemporal_Single() + { + var test = new LoadPairVector128NonTemporal_Single(); + + if (test.IsSupported) + { + // Validates basic functionality works + test.RunBasicScenario_Load(); + + // Validates calling via reflection works + test.RunReflectionScenario_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 LoadPairVector128NonTemporal_Single + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray1; + private byte[] outArray2; + + private GCHandle inHandle1; + private GCHandle outHandle1; + private GCHandle outHandle2; + + private ulong alignment; + + public DataTable(Single[] inArray1, Single[] outArray1, Single[] outArray2, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray1 = outArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray2 = outArray2.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 32) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray1 || (alignment * 2) < sizeOfoutArray2) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray1 = new byte[alignment * 2]; + this.outArray2 = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle1 = GCHandle.Alloc(this.outArray1, GCHandleType.Pinned); + this.outHandle2 = GCHandle.Alloc(this.outArray2, 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* outArray1Ptr => Align((byte*)(outHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArray2Ptr => Align((byte*)(outHandle2.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle1.Free(); + outHandle2.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private static readonly int LargestVectorSize = 32; + + private static readonly int Ret1ElementCount = Unsafe.SizeOf>() / sizeof(Single); + private static readonly int Ret2ElementCount = Unsafe.SizeOf>() / sizeof(Single); + private static readonly int Op1ElementCount = Ret1ElementCount + Ret2ElementCount; + + private static Single[] _data = new Single[Op1ElementCount]; + + private DataTable _dataTable; + + public LoadPairVector128NonTemporal_Single() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetSingle(); } + _dataTable = new DataTable(_data, new Single[Ret1ElementCount], new Single[Ret2ElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var (value1, value2) = AdvSimd.Arm64.LoadPairVector128NonTemporal((Single*)(_dataTable.inArray1Ptr)); + Unsafe.Write(_dataTable.outArray1Ptr, value1); + Unsafe.Write(_dataTable.outArray2Ptr, value2); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArray1Ptr, _dataTable.outArray2Ptr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.LoadPairVector128NonTemporal), new Type[] { typeof(Single*) }) + .Invoke(null, new object[] { + Pointer.Box(_dataTable.inArray1Ptr, typeof(Single*)) + }); + + var (value1, value2) = ((Vector128, Vector128))result; + + Unsafe.Write(_dataTable.outArray1Ptr, value1); + Unsafe.Write(_dataTable.outArray2Ptr, value2); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArray1Ptr, _dataTable.outArray2Ptr); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + Succeeded = false; + + try + { + RunBasicScenario_Load(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(void* firstOp, void* result1, void* result2, [CallerMemberName] string method = "") + { + Single[] inArray = new Single[Op1ElementCount]; + Single[] outArray1 = new Single[Ret1ElementCount]; + Single[] outArray2 = new Single[Ret2ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)(Unsafe.SizeOf() * Op1ElementCount)); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray1[0]), ref Unsafe.AsRef(result1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray2[0]), ref Unsafe.AsRef(result2), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray1, outArray2, method); + } + + private void ValidateResult(Single[] firstOp, Single[] firstResult, Single[] secondResult, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (int i = 0; i < Op1ElementCount; i++) + { + if (BitConverter.SingleToInt32Bits(firstOp[i]) != BitConverter.SingleToInt32Bits(Helpers.Concat(firstResult, secondResult, i))) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.LoadPairVector128NonTemporal)}(Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" firstResult: ({string.Join(", ", firstResult)})"); + TestLibrary.TestFramework.LogInformation($"secondResult: ({string.Join(", ", secondResult)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector128NonTemporal.UInt16.cs b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector128NonTemporal.UInt16.cs new file mode 100644 index 00000000000000..a6d070bacbe3d0 --- /dev/null +++ b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector128NonTemporal.UInt16.cs @@ -0,0 +1,203 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Reflection; +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 LoadPairVector128NonTemporal_UInt16() + { + var test = new LoadPairVector128NonTemporal_UInt16(); + + if (test.IsSupported) + { + // Validates basic functionality works + test.RunBasicScenario_Load(); + + // Validates calling via reflection works + test.RunReflectionScenario_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 LoadPairVector128NonTemporal_UInt16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray1; + private byte[] outArray2; + + private GCHandle inHandle1; + private GCHandle outHandle1; + private GCHandle outHandle2; + + private ulong alignment; + + public DataTable(UInt16[] inArray1, UInt16[] outArray1, UInt16[] outArray2, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray1 = outArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray2 = outArray2.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 32) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray1 || (alignment * 2) < sizeOfoutArray2) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray1 = new byte[alignment * 2]; + this.outArray2 = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle1 = GCHandle.Alloc(this.outArray1, GCHandleType.Pinned); + this.outHandle2 = GCHandle.Alloc(this.outArray2, 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* outArray1Ptr => Align((byte*)(outHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArray2Ptr => Align((byte*)(outHandle2.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle1.Free(); + outHandle2.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private static readonly int LargestVectorSize = 32; + + private static readonly int Ret1ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int Ret2ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int Op1ElementCount = Ret1ElementCount + Ret2ElementCount; + + private static UInt16[] _data = new UInt16[Op1ElementCount]; + + private DataTable _dataTable; + + public LoadPairVector128NonTemporal_UInt16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt16(); } + _dataTable = new DataTable(_data, new UInt16[Ret1ElementCount], new UInt16[Ret2ElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var (value1, value2) = AdvSimd.Arm64.LoadPairVector128NonTemporal((UInt16*)(_dataTable.inArray1Ptr)); + Unsafe.Write(_dataTable.outArray1Ptr, value1); + Unsafe.Write(_dataTable.outArray2Ptr, value2); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArray1Ptr, _dataTable.outArray2Ptr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.LoadPairVector128NonTemporal), new Type[] { typeof(UInt16*) }) + .Invoke(null, new object[] { + Pointer.Box(_dataTable.inArray1Ptr, typeof(UInt16*)) + }); + + var (value1, value2) = ((Vector128, Vector128))result; + + Unsafe.Write(_dataTable.outArray1Ptr, value1); + Unsafe.Write(_dataTable.outArray2Ptr, value2); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArray1Ptr, _dataTable.outArray2Ptr); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + Succeeded = false; + + try + { + RunBasicScenario_Load(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(void* firstOp, void* result1, void* result2, [CallerMemberName] string method = "") + { + UInt16[] inArray = new UInt16[Op1ElementCount]; + UInt16[] outArray1 = new UInt16[Ret1ElementCount]; + UInt16[] outArray2 = new UInt16[Ret2ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)(Unsafe.SizeOf() * Op1ElementCount)); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray1[0]), ref Unsafe.AsRef(result1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray2[0]), ref Unsafe.AsRef(result2), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray1, outArray2, method); + } + + private void ValidateResult(UInt16[] firstOp, UInt16[] firstResult, UInt16[] secondResult, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (int i = 0; i < Op1ElementCount; i++) + { + if (firstOp[i] != Helpers.Concat(firstResult, secondResult, i)) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.LoadPairVector128NonTemporal)}(Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" firstResult: ({string.Join(", ", firstResult)})"); + TestLibrary.TestFramework.LogInformation($"secondResult: ({string.Join(", ", secondResult)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector128NonTemporal.UInt32.cs b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector128NonTemporal.UInt32.cs new file mode 100644 index 00000000000000..2541718704d429 --- /dev/null +++ b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector128NonTemporal.UInt32.cs @@ -0,0 +1,203 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Reflection; +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 LoadPairVector128NonTemporal_UInt32() + { + var test = new LoadPairVector128NonTemporal_UInt32(); + + if (test.IsSupported) + { + // Validates basic functionality works + test.RunBasicScenario_Load(); + + // Validates calling via reflection works + test.RunReflectionScenario_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 LoadPairVector128NonTemporal_UInt32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray1; + private byte[] outArray2; + + private GCHandle inHandle1; + private GCHandle outHandle1; + private GCHandle outHandle2; + + private ulong alignment; + + public DataTable(UInt32[] inArray1, UInt32[] outArray1, UInt32[] outArray2, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray1 = outArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray2 = outArray2.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 32) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray1 || (alignment * 2) < sizeOfoutArray2) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray1 = new byte[alignment * 2]; + this.outArray2 = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle1 = GCHandle.Alloc(this.outArray1, GCHandleType.Pinned); + this.outHandle2 = GCHandle.Alloc(this.outArray2, 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* outArray1Ptr => Align((byte*)(outHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArray2Ptr => Align((byte*)(outHandle2.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle1.Free(); + outHandle2.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private static readonly int LargestVectorSize = 32; + + private static readonly int Ret1ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int Ret2ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int Op1ElementCount = Ret1ElementCount + Ret2ElementCount; + + private static UInt32[] _data = new UInt32[Op1ElementCount]; + + private DataTable _dataTable; + + public LoadPairVector128NonTemporal_UInt32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt32(); } + _dataTable = new DataTable(_data, new UInt32[Ret1ElementCount], new UInt32[Ret2ElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var (value1, value2) = AdvSimd.Arm64.LoadPairVector128NonTemporal((UInt32*)(_dataTable.inArray1Ptr)); + Unsafe.Write(_dataTable.outArray1Ptr, value1); + Unsafe.Write(_dataTable.outArray2Ptr, value2); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArray1Ptr, _dataTable.outArray2Ptr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.LoadPairVector128NonTemporal), new Type[] { typeof(UInt32*) }) + .Invoke(null, new object[] { + Pointer.Box(_dataTable.inArray1Ptr, typeof(UInt32*)) + }); + + var (value1, value2) = ((Vector128, Vector128))result; + + Unsafe.Write(_dataTable.outArray1Ptr, value1); + Unsafe.Write(_dataTable.outArray2Ptr, value2); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArray1Ptr, _dataTable.outArray2Ptr); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + Succeeded = false; + + try + { + RunBasicScenario_Load(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(void* firstOp, void* result1, void* result2, [CallerMemberName] string method = "") + { + UInt32[] inArray = new UInt32[Op1ElementCount]; + UInt32[] outArray1 = new UInt32[Ret1ElementCount]; + UInt32[] outArray2 = new UInt32[Ret2ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)(Unsafe.SizeOf() * Op1ElementCount)); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray1[0]), ref Unsafe.AsRef(result1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray2[0]), ref Unsafe.AsRef(result2), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray1, outArray2, method); + } + + private void ValidateResult(UInt32[] firstOp, UInt32[] firstResult, UInt32[] secondResult, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (int i = 0; i < Op1ElementCount; i++) + { + if (firstOp[i] != Helpers.Concat(firstResult, secondResult, i)) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.LoadPairVector128NonTemporal)}(Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" firstResult: ({string.Join(", ", firstResult)})"); + TestLibrary.TestFramework.LogInformation($"secondResult: ({string.Join(", ", secondResult)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector128NonTemporal.UInt64.cs b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector128NonTemporal.UInt64.cs new file mode 100644 index 00000000000000..f4f3cd80ef8592 --- /dev/null +++ b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector128NonTemporal.UInt64.cs @@ -0,0 +1,203 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Reflection; +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 LoadPairVector128NonTemporal_UInt64() + { + var test = new LoadPairVector128NonTemporal_UInt64(); + + if (test.IsSupported) + { + // Validates basic functionality works + test.RunBasicScenario_Load(); + + // Validates calling via reflection works + test.RunReflectionScenario_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 LoadPairVector128NonTemporal_UInt64 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray1; + private byte[] outArray2; + + private GCHandle inHandle1; + private GCHandle outHandle1; + private GCHandle outHandle2; + + private ulong alignment; + + public DataTable(UInt64[] inArray1, UInt64[] outArray1, UInt64[] outArray2, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray1 = outArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray2 = outArray2.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 32) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray1 || (alignment * 2) < sizeOfoutArray2) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray1 = new byte[alignment * 2]; + this.outArray2 = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle1 = GCHandle.Alloc(this.outArray1, GCHandleType.Pinned); + this.outHandle2 = GCHandle.Alloc(this.outArray2, 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* outArray1Ptr => Align((byte*)(outHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArray2Ptr => Align((byte*)(outHandle2.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle1.Free(); + outHandle2.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private static readonly int LargestVectorSize = 32; + + private static readonly int Ret1ElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + private static readonly int Ret2ElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + private static readonly int Op1ElementCount = Ret1ElementCount + Ret2ElementCount; + + private static UInt64[] _data = new UInt64[Op1ElementCount]; + + private DataTable _dataTable; + + public LoadPairVector128NonTemporal_UInt64() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt64(); } + _dataTable = new DataTable(_data, new UInt64[Ret1ElementCount], new UInt64[Ret2ElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var (value1, value2) = AdvSimd.Arm64.LoadPairVector128NonTemporal((UInt64*)(_dataTable.inArray1Ptr)); + Unsafe.Write(_dataTable.outArray1Ptr, value1); + Unsafe.Write(_dataTable.outArray2Ptr, value2); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArray1Ptr, _dataTable.outArray2Ptr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.LoadPairVector128NonTemporal), new Type[] { typeof(UInt64*) }) + .Invoke(null, new object[] { + Pointer.Box(_dataTable.inArray1Ptr, typeof(UInt64*)) + }); + + var (value1, value2) = ((Vector128, Vector128))result; + + Unsafe.Write(_dataTable.outArray1Ptr, value1); + Unsafe.Write(_dataTable.outArray2Ptr, value2); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArray1Ptr, _dataTable.outArray2Ptr); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + Succeeded = false; + + try + { + RunBasicScenario_Load(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(void* firstOp, void* result1, void* result2, [CallerMemberName] string method = "") + { + UInt64[] inArray = new UInt64[Op1ElementCount]; + UInt64[] outArray1 = new UInt64[Ret1ElementCount]; + UInt64[] outArray2 = new UInt64[Ret2ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)(Unsafe.SizeOf() * Op1ElementCount)); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray1[0]), ref Unsafe.AsRef(result1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray2[0]), ref Unsafe.AsRef(result2), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray1, outArray2, method); + } + + private void ValidateResult(UInt64[] firstOp, UInt64[] firstResult, UInt64[] secondResult, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (int i = 0; i < Op1ElementCount; i++) + { + if (firstOp[i] != Helpers.Concat(firstResult, secondResult, i)) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.LoadPairVector128NonTemporal)}(Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" firstResult: ({string.Join(", ", firstResult)})"); + TestLibrary.TestFramework.LogInformation($"secondResult: ({string.Join(", ", secondResult)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector64.Byte.cs b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector64.Byte.cs new file mode 100644 index 00000000000000..c49afaab4db6e4 --- /dev/null +++ b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector64.Byte.cs @@ -0,0 +1,203 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Reflection; +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 LoadPairVector64_Byte() + { + var test = new LoadPairVector64_Byte(); + + if (test.IsSupported) + { + // Validates basic functionality works + test.RunBasicScenario_Load(); + + // Validates calling via reflection works + test.RunReflectionScenario_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 LoadPairVector64_Byte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray1; + private byte[] outArray2; + + private GCHandle inHandle1; + private GCHandle outHandle1; + private GCHandle outHandle2; + + private ulong alignment; + + public DataTable(Byte[] inArray1, Byte[] outArray1, Byte[] outArray2, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray1 = outArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray2 = outArray2.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 32) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray1 || (alignment * 2) < sizeOfoutArray2) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray1 = new byte[alignment * 2]; + this.outArray2 = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle1 = GCHandle.Alloc(this.outArray1, GCHandleType.Pinned); + this.outHandle2 = GCHandle.Alloc(this.outArray2, 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* outArray1Ptr => Align((byte*)(outHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArray2Ptr => Align((byte*)(outHandle2.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle1.Free(); + outHandle2.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Ret1ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int Ret2ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int Op1ElementCount = Ret1ElementCount + Ret2ElementCount; + + private static Byte[] _data = new Byte[Op1ElementCount]; + + private DataTable _dataTable; + + public LoadPairVector64_Byte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetByte(); } + _dataTable = new DataTable(_data, new Byte[Ret1ElementCount], new Byte[Ret2ElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var (value1, value2) = AdvSimd.Arm64.LoadPairVector64((Byte*)(_dataTable.inArray1Ptr)); + Unsafe.Write(_dataTable.outArray1Ptr, value1); + Unsafe.Write(_dataTable.outArray2Ptr, value2); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArray1Ptr, _dataTable.outArray2Ptr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.LoadPairVector64), new Type[] { typeof(Byte*) }) + .Invoke(null, new object[] { + Pointer.Box(_dataTable.inArray1Ptr, typeof(Byte*)) + }); + + var (value1, value2) = ((Vector64, Vector64))result; + + Unsafe.Write(_dataTable.outArray1Ptr, value1); + Unsafe.Write(_dataTable.outArray2Ptr, value2); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArray1Ptr, _dataTable.outArray2Ptr); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + Succeeded = false; + + try + { + RunBasicScenario_Load(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(void* firstOp, void* result1, void* result2, [CallerMemberName] string method = "") + { + Byte[] inArray = new Byte[Op1ElementCount]; + Byte[] outArray1 = new Byte[Ret1ElementCount]; + Byte[] outArray2 = new Byte[Ret2ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)(Unsafe.SizeOf() * Op1ElementCount)); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray1[0]), ref Unsafe.AsRef(result1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray2[0]), ref Unsafe.AsRef(result2), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray1, outArray2, method); + } + + private void ValidateResult(Byte[] firstOp, Byte[] firstResult, Byte[] secondResult, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (int i = 0; i < Op1ElementCount; i++) + { + if (firstOp[i] != Helpers.Concat(firstResult, secondResult, i)) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.LoadPairVector64)}(Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" firstResult: ({string.Join(", ", firstResult)})"); + TestLibrary.TestFramework.LogInformation($"secondResult: ({string.Join(", ", secondResult)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector64.Double.cs b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector64.Double.cs new file mode 100644 index 00000000000000..6131cf1b01e830 --- /dev/null +++ b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector64.Double.cs @@ -0,0 +1,203 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Reflection; +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 LoadPairVector64_Double() + { + var test = new LoadPairVector64_Double(); + + if (test.IsSupported) + { + // Validates basic functionality works + test.RunBasicScenario_Load(); + + // Validates calling via reflection works + test.RunReflectionScenario_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 LoadPairVector64_Double + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray1; + private byte[] outArray2; + + private GCHandle inHandle1; + private GCHandle outHandle1; + private GCHandle outHandle2; + + private ulong alignment; + + public DataTable(Double[] inArray1, Double[] outArray1, Double[] outArray2, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray1 = outArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray2 = outArray2.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 32) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray1 || (alignment * 2) < sizeOfoutArray2) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray1 = new byte[alignment * 2]; + this.outArray2 = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle1 = GCHandle.Alloc(this.outArray1, GCHandleType.Pinned); + this.outHandle2 = GCHandle.Alloc(this.outArray2, 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* outArray1Ptr => Align((byte*)(outHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArray2Ptr => Align((byte*)(outHandle2.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle1.Free(); + outHandle2.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Ret1ElementCount = Unsafe.SizeOf>() / sizeof(Double); + private static readonly int Ret2ElementCount = Unsafe.SizeOf>() / sizeof(Double); + private static readonly int Op1ElementCount = Ret1ElementCount + Ret2ElementCount; + + private static Double[] _data = new Double[Op1ElementCount]; + + private DataTable _dataTable; + + public LoadPairVector64_Double() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetDouble(); } + _dataTable = new DataTable(_data, new Double[Ret1ElementCount], new Double[Ret2ElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var (value1, value2) = AdvSimd.Arm64.LoadPairVector64((Double*)(_dataTable.inArray1Ptr)); + Unsafe.Write(_dataTable.outArray1Ptr, value1); + Unsafe.Write(_dataTable.outArray2Ptr, value2); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArray1Ptr, _dataTable.outArray2Ptr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.LoadPairVector64), new Type[] { typeof(Double*) }) + .Invoke(null, new object[] { + Pointer.Box(_dataTable.inArray1Ptr, typeof(Double*)) + }); + + var (value1, value2) = ((Vector64, Vector64))result; + + Unsafe.Write(_dataTable.outArray1Ptr, value1); + Unsafe.Write(_dataTable.outArray2Ptr, value2); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArray1Ptr, _dataTable.outArray2Ptr); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + Succeeded = false; + + try + { + RunBasicScenario_Load(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(void* firstOp, void* result1, void* result2, [CallerMemberName] string method = "") + { + Double[] inArray = new Double[Op1ElementCount]; + Double[] outArray1 = new Double[Ret1ElementCount]; + Double[] outArray2 = new Double[Ret2ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)(Unsafe.SizeOf() * Op1ElementCount)); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray1[0]), ref Unsafe.AsRef(result1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray2[0]), ref Unsafe.AsRef(result2), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray1, outArray2, method); + } + + private void ValidateResult(Double[] firstOp, Double[] firstResult, Double[] secondResult, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (int i = 0; i < Op1ElementCount; i++) + { + if (BitConverter.DoubleToInt64Bits(firstOp[i]) != BitConverter.DoubleToInt64Bits(Helpers.Concat(firstResult, secondResult, i))) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.LoadPairVector64)}(Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" firstResult: ({string.Join(", ", firstResult)})"); + TestLibrary.TestFramework.LogInformation($"secondResult: ({string.Join(", ", secondResult)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector64.Int16.cs b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector64.Int16.cs new file mode 100644 index 00000000000000..a1010538676460 --- /dev/null +++ b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector64.Int16.cs @@ -0,0 +1,203 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Reflection; +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 LoadPairVector64_Int16() + { + var test = new LoadPairVector64_Int16(); + + if (test.IsSupported) + { + // Validates basic functionality works + test.RunBasicScenario_Load(); + + // Validates calling via reflection works + test.RunReflectionScenario_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 LoadPairVector64_Int16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray1; + private byte[] outArray2; + + private GCHandle inHandle1; + private GCHandle outHandle1; + private GCHandle outHandle2; + + private ulong alignment; + + public DataTable(Int16[] inArray1, Int16[] outArray1, Int16[] outArray2, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray1 = outArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray2 = outArray2.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 32) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray1 || (alignment * 2) < sizeOfoutArray2) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray1 = new byte[alignment * 2]; + this.outArray2 = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle1 = GCHandle.Alloc(this.outArray1, GCHandleType.Pinned); + this.outHandle2 = GCHandle.Alloc(this.outArray2, 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* outArray1Ptr => Align((byte*)(outHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArray2Ptr => Align((byte*)(outHandle2.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle1.Free(); + outHandle2.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Ret1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int Ret2ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int Op1ElementCount = Ret1ElementCount + Ret2ElementCount; + + private static Int16[] _data = new Int16[Op1ElementCount]; + + private DataTable _dataTable; + + public LoadPairVector64_Int16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data, new Int16[Ret1ElementCount], new Int16[Ret2ElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var (value1, value2) = AdvSimd.Arm64.LoadPairVector64((Int16*)(_dataTable.inArray1Ptr)); + Unsafe.Write(_dataTable.outArray1Ptr, value1); + Unsafe.Write(_dataTable.outArray2Ptr, value2); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArray1Ptr, _dataTable.outArray2Ptr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.LoadPairVector64), new Type[] { typeof(Int16*) }) + .Invoke(null, new object[] { + Pointer.Box(_dataTable.inArray1Ptr, typeof(Int16*)) + }); + + var (value1, value2) = ((Vector64, Vector64))result; + + Unsafe.Write(_dataTable.outArray1Ptr, value1); + Unsafe.Write(_dataTable.outArray2Ptr, value2); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArray1Ptr, _dataTable.outArray2Ptr); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + Succeeded = false; + + try + { + RunBasicScenario_Load(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(void* firstOp, void* result1, void* result2, [CallerMemberName] string method = "") + { + Int16[] inArray = new Int16[Op1ElementCount]; + Int16[] outArray1 = new Int16[Ret1ElementCount]; + Int16[] outArray2 = new Int16[Ret2ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)(Unsafe.SizeOf() * Op1ElementCount)); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray1[0]), ref Unsafe.AsRef(result1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray2[0]), ref Unsafe.AsRef(result2), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray1, outArray2, method); + } + + private void ValidateResult(Int16[] firstOp, Int16[] firstResult, Int16[] secondResult, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (int i = 0; i < Op1ElementCount; i++) + { + if (firstOp[i] != Helpers.Concat(firstResult, secondResult, i)) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.LoadPairVector64)}(Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" firstResult: ({string.Join(", ", firstResult)})"); + TestLibrary.TestFramework.LogInformation($"secondResult: ({string.Join(", ", secondResult)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector64.Int32.cs b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector64.Int32.cs new file mode 100644 index 00000000000000..6dc5e14718cd6e --- /dev/null +++ b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector64.Int32.cs @@ -0,0 +1,203 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Reflection; +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 LoadPairVector64_Int32() + { + var test = new LoadPairVector64_Int32(); + + if (test.IsSupported) + { + // Validates basic functionality works + test.RunBasicScenario_Load(); + + // Validates calling via reflection works + test.RunReflectionScenario_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 LoadPairVector64_Int32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray1; + private byte[] outArray2; + + private GCHandle inHandle1; + private GCHandle outHandle1; + private GCHandle outHandle2; + + private ulong alignment; + + public DataTable(Int32[] inArray1, Int32[] outArray1, Int32[] outArray2, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray1 = outArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray2 = outArray2.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 32) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray1 || (alignment * 2) < sizeOfoutArray2) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray1 = new byte[alignment * 2]; + this.outArray2 = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle1 = GCHandle.Alloc(this.outArray1, GCHandleType.Pinned); + this.outHandle2 = GCHandle.Alloc(this.outArray2, 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* outArray1Ptr => Align((byte*)(outHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArray2Ptr => Align((byte*)(outHandle2.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle1.Free(); + outHandle2.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Ret1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int Ret2ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int Op1ElementCount = Ret1ElementCount + Ret2ElementCount; + + private static Int32[] _data = new Int32[Op1ElementCount]; + + private DataTable _dataTable; + + public LoadPairVector64_Int32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data, new Int32[Ret1ElementCount], new Int32[Ret2ElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var (value1, value2) = AdvSimd.Arm64.LoadPairVector64((Int32*)(_dataTable.inArray1Ptr)); + Unsafe.Write(_dataTable.outArray1Ptr, value1); + Unsafe.Write(_dataTable.outArray2Ptr, value2); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArray1Ptr, _dataTable.outArray2Ptr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.LoadPairVector64), new Type[] { typeof(Int32*) }) + .Invoke(null, new object[] { + Pointer.Box(_dataTable.inArray1Ptr, typeof(Int32*)) + }); + + var (value1, value2) = ((Vector64, Vector64))result; + + Unsafe.Write(_dataTable.outArray1Ptr, value1); + Unsafe.Write(_dataTable.outArray2Ptr, value2); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArray1Ptr, _dataTable.outArray2Ptr); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + Succeeded = false; + + try + { + RunBasicScenario_Load(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(void* firstOp, void* result1, void* result2, [CallerMemberName] string method = "") + { + Int32[] inArray = new Int32[Op1ElementCount]; + Int32[] outArray1 = new Int32[Ret1ElementCount]; + Int32[] outArray2 = new Int32[Ret2ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)(Unsafe.SizeOf() * Op1ElementCount)); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray1[0]), ref Unsafe.AsRef(result1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray2[0]), ref Unsafe.AsRef(result2), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray1, outArray2, method); + } + + private void ValidateResult(Int32[] firstOp, Int32[] firstResult, Int32[] secondResult, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (int i = 0; i < Op1ElementCount; i++) + { + if (firstOp[i] != Helpers.Concat(firstResult, secondResult, i)) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.LoadPairVector64)}(Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" firstResult: ({string.Join(", ", firstResult)})"); + TestLibrary.TestFramework.LogInformation($"secondResult: ({string.Join(", ", secondResult)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector64.Int64.cs b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector64.Int64.cs new file mode 100644 index 00000000000000..ab68029393ef60 --- /dev/null +++ b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector64.Int64.cs @@ -0,0 +1,203 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Reflection; +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 LoadPairVector64_Int64() + { + var test = new LoadPairVector64_Int64(); + + if (test.IsSupported) + { + // Validates basic functionality works + test.RunBasicScenario_Load(); + + // Validates calling via reflection works + test.RunReflectionScenario_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 LoadPairVector64_Int64 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray1; + private byte[] outArray2; + + private GCHandle inHandle1; + private GCHandle outHandle1; + private GCHandle outHandle2; + + private ulong alignment; + + public DataTable(Int64[] inArray1, Int64[] outArray1, Int64[] outArray2, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray1 = outArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray2 = outArray2.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 32) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray1 || (alignment * 2) < sizeOfoutArray2) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray1 = new byte[alignment * 2]; + this.outArray2 = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle1 = GCHandle.Alloc(this.outArray1, GCHandleType.Pinned); + this.outHandle2 = GCHandle.Alloc(this.outArray2, 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* outArray1Ptr => Align((byte*)(outHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArray2Ptr => Align((byte*)(outHandle2.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle1.Free(); + outHandle2.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Ret1ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int Ret2ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int Op1ElementCount = Ret1ElementCount + Ret2ElementCount; + + private static Int64[] _data = new Int64[Op1ElementCount]; + + private DataTable _dataTable; + + public LoadPairVector64_Int64() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + _dataTable = new DataTable(_data, new Int64[Ret1ElementCount], new Int64[Ret2ElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var (value1, value2) = AdvSimd.Arm64.LoadPairVector64((Int64*)(_dataTable.inArray1Ptr)); + Unsafe.Write(_dataTable.outArray1Ptr, value1); + Unsafe.Write(_dataTable.outArray2Ptr, value2); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArray1Ptr, _dataTable.outArray2Ptr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.LoadPairVector64), new Type[] { typeof(Int64*) }) + .Invoke(null, new object[] { + Pointer.Box(_dataTable.inArray1Ptr, typeof(Int64*)) + }); + + var (value1, value2) = ((Vector64, Vector64))result; + + Unsafe.Write(_dataTable.outArray1Ptr, value1); + Unsafe.Write(_dataTable.outArray2Ptr, value2); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArray1Ptr, _dataTable.outArray2Ptr); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + Succeeded = false; + + try + { + RunBasicScenario_Load(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(void* firstOp, void* result1, void* result2, [CallerMemberName] string method = "") + { + Int64[] inArray = new Int64[Op1ElementCount]; + Int64[] outArray1 = new Int64[Ret1ElementCount]; + Int64[] outArray2 = new Int64[Ret2ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)(Unsafe.SizeOf() * Op1ElementCount)); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray1[0]), ref Unsafe.AsRef(result1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray2[0]), ref Unsafe.AsRef(result2), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray1, outArray2, method); + } + + private void ValidateResult(Int64[] firstOp, Int64[] firstResult, Int64[] secondResult, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (int i = 0; i < Op1ElementCount; i++) + { + if (firstOp[i] != Helpers.Concat(firstResult, secondResult, i)) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.LoadPairVector64)}(Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" firstResult: ({string.Join(", ", firstResult)})"); + TestLibrary.TestFramework.LogInformation($"secondResult: ({string.Join(", ", secondResult)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector64.SByte.cs b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector64.SByte.cs new file mode 100644 index 00000000000000..730fe9ce30ea82 --- /dev/null +++ b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector64.SByte.cs @@ -0,0 +1,203 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Reflection; +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 LoadPairVector64_SByte() + { + var test = new LoadPairVector64_SByte(); + + if (test.IsSupported) + { + // Validates basic functionality works + test.RunBasicScenario_Load(); + + // Validates calling via reflection works + test.RunReflectionScenario_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 LoadPairVector64_SByte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray1; + private byte[] outArray2; + + private GCHandle inHandle1; + private GCHandle outHandle1; + private GCHandle outHandle2; + + private ulong alignment; + + public DataTable(SByte[] inArray1, SByte[] outArray1, SByte[] outArray2, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray1 = outArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray2 = outArray2.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 32) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray1 || (alignment * 2) < sizeOfoutArray2) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray1 = new byte[alignment * 2]; + this.outArray2 = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle1 = GCHandle.Alloc(this.outArray1, GCHandleType.Pinned); + this.outHandle2 = GCHandle.Alloc(this.outArray2, 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* outArray1Ptr => Align((byte*)(outHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArray2Ptr => Align((byte*)(outHandle2.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle1.Free(); + outHandle2.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Ret1ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int Ret2ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int Op1ElementCount = Ret1ElementCount + Ret2ElementCount; + + private static SByte[] _data = new SByte[Op1ElementCount]; + + private DataTable _dataTable; + + public LoadPairVector64_SByte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data, new SByte[Ret1ElementCount], new SByte[Ret2ElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var (value1, value2) = AdvSimd.Arm64.LoadPairVector64((SByte*)(_dataTable.inArray1Ptr)); + Unsafe.Write(_dataTable.outArray1Ptr, value1); + Unsafe.Write(_dataTable.outArray2Ptr, value2); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArray1Ptr, _dataTable.outArray2Ptr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.LoadPairVector64), new Type[] { typeof(SByte*) }) + .Invoke(null, new object[] { + Pointer.Box(_dataTable.inArray1Ptr, typeof(SByte*)) + }); + + var (value1, value2) = ((Vector64, Vector64))result; + + Unsafe.Write(_dataTable.outArray1Ptr, value1); + Unsafe.Write(_dataTable.outArray2Ptr, value2); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArray1Ptr, _dataTable.outArray2Ptr); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + Succeeded = false; + + try + { + RunBasicScenario_Load(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(void* firstOp, void* result1, void* result2, [CallerMemberName] string method = "") + { + SByte[] inArray = new SByte[Op1ElementCount]; + SByte[] outArray1 = new SByte[Ret1ElementCount]; + SByte[] outArray2 = new SByte[Ret2ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)(Unsafe.SizeOf() * Op1ElementCount)); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray1[0]), ref Unsafe.AsRef(result1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray2[0]), ref Unsafe.AsRef(result2), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray1, outArray2, method); + } + + private void ValidateResult(SByte[] firstOp, SByte[] firstResult, SByte[] secondResult, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (int i = 0; i < Op1ElementCount; i++) + { + if (firstOp[i] != Helpers.Concat(firstResult, secondResult, i)) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.LoadPairVector64)}(Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" firstResult: ({string.Join(", ", firstResult)})"); + TestLibrary.TestFramework.LogInformation($"secondResult: ({string.Join(", ", secondResult)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector64.Single.cs b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector64.Single.cs new file mode 100644 index 00000000000000..d04a0156029697 --- /dev/null +++ b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector64.Single.cs @@ -0,0 +1,203 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Reflection; +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 LoadPairVector64_Single() + { + var test = new LoadPairVector64_Single(); + + if (test.IsSupported) + { + // Validates basic functionality works + test.RunBasicScenario_Load(); + + // Validates calling via reflection works + test.RunReflectionScenario_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 LoadPairVector64_Single + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray1; + private byte[] outArray2; + + private GCHandle inHandle1; + private GCHandle outHandle1; + private GCHandle outHandle2; + + private ulong alignment; + + public DataTable(Single[] inArray1, Single[] outArray1, Single[] outArray2, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray1 = outArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray2 = outArray2.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 32) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray1 || (alignment * 2) < sizeOfoutArray2) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray1 = new byte[alignment * 2]; + this.outArray2 = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle1 = GCHandle.Alloc(this.outArray1, GCHandleType.Pinned); + this.outHandle2 = GCHandle.Alloc(this.outArray2, 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* outArray1Ptr => Align((byte*)(outHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArray2Ptr => Align((byte*)(outHandle2.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle1.Free(); + outHandle2.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Ret1ElementCount = Unsafe.SizeOf>() / sizeof(Single); + private static readonly int Ret2ElementCount = Unsafe.SizeOf>() / sizeof(Single); + private static readonly int Op1ElementCount = Ret1ElementCount + Ret2ElementCount; + + private static Single[] _data = new Single[Op1ElementCount]; + + private DataTable _dataTable; + + public LoadPairVector64_Single() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetSingle(); } + _dataTable = new DataTable(_data, new Single[Ret1ElementCount], new Single[Ret2ElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var (value1, value2) = AdvSimd.Arm64.LoadPairVector64((Single*)(_dataTable.inArray1Ptr)); + Unsafe.Write(_dataTable.outArray1Ptr, value1); + Unsafe.Write(_dataTable.outArray2Ptr, value2); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArray1Ptr, _dataTable.outArray2Ptr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.LoadPairVector64), new Type[] { typeof(Single*) }) + .Invoke(null, new object[] { + Pointer.Box(_dataTable.inArray1Ptr, typeof(Single*)) + }); + + var (value1, value2) = ((Vector64, Vector64))result; + + Unsafe.Write(_dataTable.outArray1Ptr, value1); + Unsafe.Write(_dataTable.outArray2Ptr, value2); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArray1Ptr, _dataTable.outArray2Ptr); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + Succeeded = false; + + try + { + RunBasicScenario_Load(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(void* firstOp, void* result1, void* result2, [CallerMemberName] string method = "") + { + Single[] inArray = new Single[Op1ElementCount]; + Single[] outArray1 = new Single[Ret1ElementCount]; + Single[] outArray2 = new Single[Ret2ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)(Unsafe.SizeOf() * Op1ElementCount)); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray1[0]), ref Unsafe.AsRef(result1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray2[0]), ref Unsafe.AsRef(result2), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray1, outArray2, method); + } + + private void ValidateResult(Single[] firstOp, Single[] firstResult, Single[] secondResult, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (int i = 0; i < Op1ElementCount; i++) + { + if (BitConverter.SingleToInt32Bits(firstOp[i]) != BitConverter.SingleToInt32Bits(Helpers.Concat(firstResult, secondResult, i))) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.LoadPairVector64)}(Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" firstResult: ({string.Join(", ", firstResult)})"); + TestLibrary.TestFramework.LogInformation($"secondResult: ({string.Join(", ", secondResult)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector64.UInt16.cs b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector64.UInt16.cs new file mode 100644 index 00000000000000..b4bc2b4049b356 --- /dev/null +++ b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector64.UInt16.cs @@ -0,0 +1,203 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Reflection; +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 LoadPairVector64_UInt16() + { + var test = new LoadPairVector64_UInt16(); + + if (test.IsSupported) + { + // Validates basic functionality works + test.RunBasicScenario_Load(); + + // Validates calling via reflection works + test.RunReflectionScenario_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 LoadPairVector64_UInt16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray1; + private byte[] outArray2; + + private GCHandle inHandle1; + private GCHandle outHandle1; + private GCHandle outHandle2; + + private ulong alignment; + + public DataTable(UInt16[] inArray1, UInt16[] outArray1, UInt16[] outArray2, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray1 = outArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray2 = outArray2.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 32) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray1 || (alignment * 2) < sizeOfoutArray2) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray1 = new byte[alignment * 2]; + this.outArray2 = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle1 = GCHandle.Alloc(this.outArray1, GCHandleType.Pinned); + this.outHandle2 = GCHandle.Alloc(this.outArray2, 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* outArray1Ptr => Align((byte*)(outHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArray2Ptr => Align((byte*)(outHandle2.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle1.Free(); + outHandle2.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Ret1ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int Ret2ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int Op1ElementCount = Ret1ElementCount + Ret2ElementCount; + + private static UInt16[] _data = new UInt16[Op1ElementCount]; + + private DataTable _dataTable; + + public LoadPairVector64_UInt16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt16(); } + _dataTable = new DataTable(_data, new UInt16[Ret1ElementCount], new UInt16[Ret2ElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var (value1, value2) = AdvSimd.Arm64.LoadPairVector64((UInt16*)(_dataTable.inArray1Ptr)); + Unsafe.Write(_dataTable.outArray1Ptr, value1); + Unsafe.Write(_dataTable.outArray2Ptr, value2); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArray1Ptr, _dataTable.outArray2Ptr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.LoadPairVector64), new Type[] { typeof(UInt16*) }) + .Invoke(null, new object[] { + Pointer.Box(_dataTable.inArray1Ptr, typeof(UInt16*)) + }); + + var (value1, value2) = ((Vector64, Vector64))result; + + Unsafe.Write(_dataTable.outArray1Ptr, value1); + Unsafe.Write(_dataTable.outArray2Ptr, value2); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArray1Ptr, _dataTable.outArray2Ptr); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + Succeeded = false; + + try + { + RunBasicScenario_Load(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(void* firstOp, void* result1, void* result2, [CallerMemberName] string method = "") + { + UInt16[] inArray = new UInt16[Op1ElementCount]; + UInt16[] outArray1 = new UInt16[Ret1ElementCount]; + UInt16[] outArray2 = new UInt16[Ret2ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)(Unsafe.SizeOf() * Op1ElementCount)); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray1[0]), ref Unsafe.AsRef(result1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray2[0]), ref Unsafe.AsRef(result2), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray1, outArray2, method); + } + + private void ValidateResult(UInt16[] firstOp, UInt16[] firstResult, UInt16[] secondResult, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (int i = 0; i < Op1ElementCount; i++) + { + if (firstOp[i] != Helpers.Concat(firstResult, secondResult, i)) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.LoadPairVector64)}(Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" firstResult: ({string.Join(", ", firstResult)})"); + TestLibrary.TestFramework.LogInformation($"secondResult: ({string.Join(", ", secondResult)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector64.UInt32.cs b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector64.UInt32.cs new file mode 100644 index 00000000000000..ff00785e891abf --- /dev/null +++ b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector64.UInt32.cs @@ -0,0 +1,203 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Reflection; +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 LoadPairVector64_UInt32() + { + var test = new LoadPairVector64_UInt32(); + + if (test.IsSupported) + { + // Validates basic functionality works + test.RunBasicScenario_Load(); + + // Validates calling via reflection works + test.RunReflectionScenario_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 LoadPairVector64_UInt32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray1; + private byte[] outArray2; + + private GCHandle inHandle1; + private GCHandle outHandle1; + private GCHandle outHandle2; + + private ulong alignment; + + public DataTable(UInt32[] inArray1, UInt32[] outArray1, UInt32[] outArray2, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray1 = outArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray2 = outArray2.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 32) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray1 || (alignment * 2) < sizeOfoutArray2) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray1 = new byte[alignment * 2]; + this.outArray2 = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle1 = GCHandle.Alloc(this.outArray1, GCHandleType.Pinned); + this.outHandle2 = GCHandle.Alloc(this.outArray2, 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* outArray1Ptr => Align((byte*)(outHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArray2Ptr => Align((byte*)(outHandle2.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle1.Free(); + outHandle2.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Ret1ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int Ret2ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int Op1ElementCount = Ret1ElementCount + Ret2ElementCount; + + private static UInt32[] _data = new UInt32[Op1ElementCount]; + + private DataTable _dataTable; + + public LoadPairVector64_UInt32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt32(); } + _dataTable = new DataTable(_data, new UInt32[Ret1ElementCount], new UInt32[Ret2ElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var (value1, value2) = AdvSimd.Arm64.LoadPairVector64((UInt32*)(_dataTable.inArray1Ptr)); + Unsafe.Write(_dataTable.outArray1Ptr, value1); + Unsafe.Write(_dataTable.outArray2Ptr, value2); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArray1Ptr, _dataTable.outArray2Ptr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.LoadPairVector64), new Type[] { typeof(UInt32*) }) + .Invoke(null, new object[] { + Pointer.Box(_dataTable.inArray1Ptr, typeof(UInt32*)) + }); + + var (value1, value2) = ((Vector64, Vector64))result; + + Unsafe.Write(_dataTable.outArray1Ptr, value1); + Unsafe.Write(_dataTable.outArray2Ptr, value2); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArray1Ptr, _dataTable.outArray2Ptr); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + Succeeded = false; + + try + { + RunBasicScenario_Load(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(void* firstOp, void* result1, void* result2, [CallerMemberName] string method = "") + { + UInt32[] inArray = new UInt32[Op1ElementCount]; + UInt32[] outArray1 = new UInt32[Ret1ElementCount]; + UInt32[] outArray2 = new UInt32[Ret2ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)(Unsafe.SizeOf() * Op1ElementCount)); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray1[0]), ref Unsafe.AsRef(result1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray2[0]), ref Unsafe.AsRef(result2), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray1, outArray2, method); + } + + private void ValidateResult(UInt32[] firstOp, UInt32[] firstResult, UInt32[] secondResult, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (int i = 0; i < Op1ElementCount; i++) + { + if (firstOp[i] != Helpers.Concat(firstResult, secondResult, i)) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.LoadPairVector64)}(Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" firstResult: ({string.Join(", ", firstResult)})"); + TestLibrary.TestFramework.LogInformation($"secondResult: ({string.Join(", ", secondResult)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector64.UInt64.cs b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector64.UInt64.cs new file mode 100644 index 00000000000000..cb8e99b52f63f2 --- /dev/null +++ b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector64.UInt64.cs @@ -0,0 +1,203 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Reflection; +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 LoadPairVector64_UInt64() + { + var test = new LoadPairVector64_UInt64(); + + if (test.IsSupported) + { + // Validates basic functionality works + test.RunBasicScenario_Load(); + + // Validates calling via reflection works + test.RunReflectionScenario_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 LoadPairVector64_UInt64 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray1; + private byte[] outArray2; + + private GCHandle inHandle1; + private GCHandle outHandle1; + private GCHandle outHandle2; + + private ulong alignment; + + public DataTable(UInt64[] inArray1, UInt64[] outArray1, UInt64[] outArray2, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray1 = outArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray2 = outArray2.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 32) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray1 || (alignment * 2) < sizeOfoutArray2) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray1 = new byte[alignment * 2]; + this.outArray2 = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle1 = GCHandle.Alloc(this.outArray1, GCHandleType.Pinned); + this.outHandle2 = GCHandle.Alloc(this.outArray2, 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* outArray1Ptr => Align((byte*)(outHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArray2Ptr => Align((byte*)(outHandle2.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle1.Free(); + outHandle2.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Ret1ElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + private static readonly int Ret2ElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + private static readonly int Op1ElementCount = Ret1ElementCount + Ret2ElementCount; + + private static UInt64[] _data = new UInt64[Op1ElementCount]; + + private DataTable _dataTable; + + public LoadPairVector64_UInt64() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt64(); } + _dataTable = new DataTable(_data, new UInt64[Ret1ElementCount], new UInt64[Ret2ElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var (value1, value2) = AdvSimd.Arm64.LoadPairVector64((UInt64*)(_dataTable.inArray1Ptr)); + Unsafe.Write(_dataTable.outArray1Ptr, value1); + Unsafe.Write(_dataTable.outArray2Ptr, value2); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArray1Ptr, _dataTable.outArray2Ptr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.LoadPairVector64), new Type[] { typeof(UInt64*) }) + .Invoke(null, new object[] { + Pointer.Box(_dataTable.inArray1Ptr, typeof(UInt64*)) + }); + + var (value1, value2) = ((Vector64, Vector64))result; + + Unsafe.Write(_dataTable.outArray1Ptr, value1); + Unsafe.Write(_dataTable.outArray2Ptr, value2); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArray1Ptr, _dataTable.outArray2Ptr); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + Succeeded = false; + + try + { + RunBasicScenario_Load(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(void* firstOp, void* result1, void* result2, [CallerMemberName] string method = "") + { + UInt64[] inArray = new UInt64[Op1ElementCount]; + UInt64[] outArray1 = new UInt64[Ret1ElementCount]; + UInt64[] outArray2 = new UInt64[Ret2ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)(Unsafe.SizeOf() * Op1ElementCount)); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray1[0]), ref Unsafe.AsRef(result1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray2[0]), ref Unsafe.AsRef(result2), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray1, outArray2, method); + } + + private void ValidateResult(UInt64[] firstOp, UInt64[] firstResult, UInt64[] secondResult, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (int i = 0; i < Op1ElementCount; i++) + { + if (firstOp[i] != Helpers.Concat(firstResult, secondResult, i)) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.LoadPairVector64)}(Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" firstResult: ({string.Join(", ", firstResult)})"); + TestLibrary.TestFramework.LogInformation($"secondResult: ({string.Join(", ", secondResult)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector64NonTemporal.Byte.cs b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector64NonTemporal.Byte.cs new file mode 100644 index 00000000000000..ca58941547fe53 --- /dev/null +++ b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector64NonTemporal.Byte.cs @@ -0,0 +1,203 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Reflection; +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 LoadPairVector64NonTemporal_Byte() + { + var test = new LoadPairVector64NonTemporal_Byte(); + + if (test.IsSupported) + { + // Validates basic functionality works + test.RunBasicScenario_Load(); + + // Validates calling via reflection works + test.RunReflectionScenario_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 LoadPairVector64NonTemporal_Byte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray1; + private byte[] outArray2; + + private GCHandle inHandle1; + private GCHandle outHandle1; + private GCHandle outHandle2; + + private ulong alignment; + + public DataTable(Byte[] inArray1, Byte[] outArray1, Byte[] outArray2, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray1 = outArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray2 = outArray2.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 32) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray1 || (alignment * 2) < sizeOfoutArray2) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray1 = new byte[alignment * 2]; + this.outArray2 = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle1 = GCHandle.Alloc(this.outArray1, GCHandleType.Pinned); + this.outHandle2 = GCHandle.Alloc(this.outArray2, 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* outArray1Ptr => Align((byte*)(outHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArray2Ptr => Align((byte*)(outHandle2.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle1.Free(); + outHandle2.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Ret1ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int Ret2ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int Op1ElementCount = Ret1ElementCount + Ret2ElementCount; + + private static Byte[] _data = new Byte[Op1ElementCount]; + + private DataTable _dataTable; + + public LoadPairVector64NonTemporal_Byte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetByte(); } + _dataTable = new DataTable(_data, new Byte[Ret1ElementCount], new Byte[Ret2ElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var (value1, value2) = AdvSimd.Arm64.LoadPairVector64NonTemporal((Byte*)(_dataTable.inArray1Ptr)); + Unsafe.Write(_dataTable.outArray1Ptr, value1); + Unsafe.Write(_dataTable.outArray2Ptr, value2); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArray1Ptr, _dataTable.outArray2Ptr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.LoadPairVector64NonTemporal), new Type[] { typeof(Byte*) }) + .Invoke(null, new object[] { + Pointer.Box(_dataTable.inArray1Ptr, typeof(Byte*)) + }); + + var (value1, value2) = ((Vector64, Vector64))result; + + Unsafe.Write(_dataTable.outArray1Ptr, value1); + Unsafe.Write(_dataTable.outArray2Ptr, value2); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArray1Ptr, _dataTable.outArray2Ptr); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + Succeeded = false; + + try + { + RunBasicScenario_Load(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(void* firstOp, void* result1, void* result2, [CallerMemberName] string method = "") + { + Byte[] inArray = new Byte[Op1ElementCount]; + Byte[] outArray1 = new Byte[Ret1ElementCount]; + Byte[] outArray2 = new Byte[Ret2ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)(Unsafe.SizeOf() * Op1ElementCount)); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray1[0]), ref Unsafe.AsRef(result1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray2[0]), ref Unsafe.AsRef(result2), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray1, outArray2, method); + } + + private void ValidateResult(Byte[] firstOp, Byte[] firstResult, Byte[] secondResult, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (int i = 0; i < Op1ElementCount; i++) + { + if (firstOp[i] != Helpers.Concat(firstResult, secondResult, i)) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.LoadPairVector64NonTemporal)}(Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" firstResult: ({string.Join(", ", firstResult)})"); + TestLibrary.TestFramework.LogInformation($"secondResult: ({string.Join(", ", secondResult)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector64NonTemporal.Double.cs b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector64NonTemporal.Double.cs new file mode 100644 index 00000000000000..218b47be70d82e --- /dev/null +++ b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector64NonTemporal.Double.cs @@ -0,0 +1,203 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Reflection; +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 LoadPairVector64NonTemporal_Double() + { + var test = new LoadPairVector64NonTemporal_Double(); + + if (test.IsSupported) + { + // Validates basic functionality works + test.RunBasicScenario_Load(); + + // Validates calling via reflection works + test.RunReflectionScenario_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 LoadPairVector64NonTemporal_Double + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray1; + private byte[] outArray2; + + private GCHandle inHandle1; + private GCHandle outHandle1; + private GCHandle outHandle2; + + private ulong alignment; + + public DataTable(Double[] inArray1, Double[] outArray1, Double[] outArray2, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray1 = outArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray2 = outArray2.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 32) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray1 || (alignment * 2) < sizeOfoutArray2) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray1 = new byte[alignment * 2]; + this.outArray2 = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle1 = GCHandle.Alloc(this.outArray1, GCHandleType.Pinned); + this.outHandle2 = GCHandle.Alloc(this.outArray2, 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* outArray1Ptr => Align((byte*)(outHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArray2Ptr => Align((byte*)(outHandle2.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle1.Free(); + outHandle2.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Ret1ElementCount = Unsafe.SizeOf>() / sizeof(Double); + private static readonly int Ret2ElementCount = Unsafe.SizeOf>() / sizeof(Double); + private static readonly int Op1ElementCount = Ret1ElementCount + Ret2ElementCount; + + private static Double[] _data = new Double[Op1ElementCount]; + + private DataTable _dataTable; + + public LoadPairVector64NonTemporal_Double() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetDouble(); } + _dataTable = new DataTable(_data, new Double[Ret1ElementCount], new Double[Ret2ElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var (value1, value2) = AdvSimd.Arm64.LoadPairVector64NonTemporal((Double*)(_dataTable.inArray1Ptr)); + Unsafe.Write(_dataTable.outArray1Ptr, value1); + Unsafe.Write(_dataTable.outArray2Ptr, value2); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArray1Ptr, _dataTable.outArray2Ptr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.LoadPairVector64NonTemporal), new Type[] { typeof(Double*) }) + .Invoke(null, new object[] { + Pointer.Box(_dataTable.inArray1Ptr, typeof(Double*)) + }); + + var (value1, value2) = ((Vector64, Vector64))result; + + Unsafe.Write(_dataTable.outArray1Ptr, value1); + Unsafe.Write(_dataTable.outArray2Ptr, value2); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArray1Ptr, _dataTable.outArray2Ptr); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + Succeeded = false; + + try + { + RunBasicScenario_Load(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(void* firstOp, void* result1, void* result2, [CallerMemberName] string method = "") + { + Double[] inArray = new Double[Op1ElementCount]; + Double[] outArray1 = new Double[Ret1ElementCount]; + Double[] outArray2 = new Double[Ret2ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)(Unsafe.SizeOf() * Op1ElementCount)); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray1[0]), ref Unsafe.AsRef(result1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray2[0]), ref Unsafe.AsRef(result2), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray1, outArray2, method); + } + + private void ValidateResult(Double[] firstOp, Double[] firstResult, Double[] secondResult, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (int i = 0; i < Op1ElementCount; i++) + { + if (BitConverter.DoubleToInt64Bits(firstOp[i]) != BitConverter.DoubleToInt64Bits(Helpers.Concat(firstResult, secondResult, i))) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.LoadPairVector64NonTemporal)}(Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" firstResult: ({string.Join(", ", firstResult)})"); + TestLibrary.TestFramework.LogInformation($"secondResult: ({string.Join(", ", secondResult)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector64NonTemporal.Int16.cs b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector64NonTemporal.Int16.cs new file mode 100644 index 00000000000000..1602ee53462f0b --- /dev/null +++ b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector64NonTemporal.Int16.cs @@ -0,0 +1,203 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Reflection; +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 LoadPairVector64NonTemporal_Int16() + { + var test = new LoadPairVector64NonTemporal_Int16(); + + if (test.IsSupported) + { + // Validates basic functionality works + test.RunBasicScenario_Load(); + + // Validates calling via reflection works + test.RunReflectionScenario_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 LoadPairVector64NonTemporal_Int16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray1; + private byte[] outArray2; + + private GCHandle inHandle1; + private GCHandle outHandle1; + private GCHandle outHandle2; + + private ulong alignment; + + public DataTable(Int16[] inArray1, Int16[] outArray1, Int16[] outArray2, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray1 = outArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray2 = outArray2.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 32) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray1 || (alignment * 2) < sizeOfoutArray2) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray1 = new byte[alignment * 2]; + this.outArray2 = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle1 = GCHandle.Alloc(this.outArray1, GCHandleType.Pinned); + this.outHandle2 = GCHandle.Alloc(this.outArray2, 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* outArray1Ptr => Align((byte*)(outHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArray2Ptr => Align((byte*)(outHandle2.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle1.Free(); + outHandle2.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Ret1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int Ret2ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int Op1ElementCount = Ret1ElementCount + Ret2ElementCount; + + private static Int16[] _data = new Int16[Op1ElementCount]; + + private DataTable _dataTable; + + public LoadPairVector64NonTemporal_Int16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data, new Int16[Ret1ElementCount], new Int16[Ret2ElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var (value1, value2) = AdvSimd.Arm64.LoadPairVector64NonTemporal((Int16*)(_dataTable.inArray1Ptr)); + Unsafe.Write(_dataTable.outArray1Ptr, value1); + Unsafe.Write(_dataTable.outArray2Ptr, value2); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArray1Ptr, _dataTable.outArray2Ptr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.LoadPairVector64NonTemporal), new Type[] { typeof(Int16*) }) + .Invoke(null, new object[] { + Pointer.Box(_dataTable.inArray1Ptr, typeof(Int16*)) + }); + + var (value1, value2) = ((Vector64, Vector64))result; + + Unsafe.Write(_dataTable.outArray1Ptr, value1); + Unsafe.Write(_dataTable.outArray2Ptr, value2); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArray1Ptr, _dataTable.outArray2Ptr); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + Succeeded = false; + + try + { + RunBasicScenario_Load(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(void* firstOp, void* result1, void* result2, [CallerMemberName] string method = "") + { + Int16[] inArray = new Int16[Op1ElementCount]; + Int16[] outArray1 = new Int16[Ret1ElementCount]; + Int16[] outArray2 = new Int16[Ret2ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)(Unsafe.SizeOf() * Op1ElementCount)); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray1[0]), ref Unsafe.AsRef(result1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray2[0]), ref Unsafe.AsRef(result2), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray1, outArray2, method); + } + + private void ValidateResult(Int16[] firstOp, Int16[] firstResult, Int16[] secondResult, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (int i = 0; i < Op1ElementCount; i++) + { + if (firstOp[i] != Helpers.Concat(firstResult, secondResult, i)) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.LoadPairVector64NonTemporal)}(Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" firstResult: ({string.Join(", ", firstResult)})"); + TestLibrary.TestFramework.LogInformation($"secondResult: ({string.Join(", ", secondResult)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector64NonTemporal.Int32.cs b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector64NonTemporal.Int32.cs new file mode 100644 index 00000000000000..cb1a5ffe3d08c4 --- /dev/null +++ b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector64NonTemporal.Int32.cs @@ -0,0 +1,203 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Reflection; +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 LoadPairVector64NonTemporal_Int32() + { + var test = new LoadPairVector64NonTemporal_Int32(); + + if (test.IsSupported) + { + // Validates basic functionality works + test.RunBasicScenario_Load(); + + // Validates calling via reflection works + test.RunReflectionScenario_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 LoadPairVector64NonTemporal_Int32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray1; + private byte[] outArray2; + + private GCHandle inHandle1; + private GCHandle outHandle1; + private GCHandle outHandle2; + + private ulong alignment; + + public DataTable(Int32[] inArray1, Int32[] outArray1, Int32[] outArray2, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray1 = outArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray2 = outArray2.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 32) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray1 || (alignment * 2) < sizeOfoutArray2) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray1 = new byte[alignment * 2]; + this.outArray2 = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle1 = GCHandle.Alloc(this.outArray1, GCHandleType.Pinned); + this.outHandle2 = GCHandle.Alloc(this.outArray2, 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* outArray1Ptr => Align((byte*)(outHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArray2Ptr => Align((byte*)(outHandle2.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle1.Free(); + outHandle2.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Ret1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int Ret2ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int Op1ElementCount = Ret1ElementCount + Ret2ElementCount; + + private static Int32[] _data = new Int32[Op1ElementCount]; + + private DataTable _dataTable; + + public LoadPairVector64NonTemporal_Int32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data, new Int32[Ret1ElementCount], new Int32[Ret2ElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var (value1, value2) = AdvSimd.Arm64.LoadPairVector64NonTemporal((Int32*)(_dataTable.inArray1Ptr)); + Unsafe.Write(_dataTable.outArray1Ptr, value1); + Unsafe.Write(_dataTable.outArray2Ptr, value2); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArray1Ptr, _dataTable.outArray2Ptr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.LoadPairVector64NonTemporal), new Type[] { typeof(Int32*) }) + .Invoke(null, new object[] { + Pointer.Box(_dataTable.inArray1Ptr, typeof(Int32*)) + }); + + var (value1, value2) = ((Vector64, Vector64))result; + + Unsafe.Write(_dataTable.outArray1Ptr, value1); + Unsafe.Write(_dataTable.outArray2Ptr, value2); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArray1Ptr, _dataTable.outArray2Ptr); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + Succeeded = false; + + try + { + RunBasicScenario_Load(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(void* firstOp, void* result1, void* result2, [CallerMemberName] string method = "") + { + Int32[] inArray = new Int32[Op1ElementCount]; + Int32[] outArray1 = new Int32[Ret1ElementCount]; + Int32[] outArray2 = new Int32[Ret2ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)(Unsafe.SizeOf() * Op1ElementCount)); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray1[0]), ref Unsafe.AsRef(result1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray2[0]), ref Unsafe.AsRef(result2), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray1, outArray2, method); + } + + private void ValidateResult(Int32[] firstOp, Int32[] firstResult, Int32[] secondResult, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (int i = 0; i < Op1ElementCount; i++) + { + if (firstOp[i] != Helpers.Concat(firstResult, secondResult, i)) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.LoadPairVector64NonTemporal)}(Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" firstResult: ({string.Join(", ", firstResult)})"); + TestLibrary.TestFramework.LogInformation($"secondResult: ({string.Join(", ", secondResult)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector64NonTemporal.Int64.cs b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector64NonTemporal.Int64.cs new file mode 100644 index 00000000000000..e5f23f7ce8f375 --- /dev/null +++ b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector64NonTemporal.Int64.cs @@ -0,0 +1,203 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Reflection; +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 LoadPairVector64NonTemporal_Int64() + { + var test = new LoadPairVector64NonTemporal_Int64(); + + if (test.IsSupported) + { + // Validates basic functionality works + test.RunBasicScenario_Load(); + + // Validates calling via reflection works + test.RunReflectionScenario_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 LoadPairVector64NonTemporal_Int64 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray1; + private byte[] outArray2; + + private GCHandle inHandle1; + private GCHandle outHandle1; + private GCHandle outHandle2; + + private ulong alignment; + + public DataTable(Int64[] inArray1, Int64[] outArray1, Int64[] outArray2, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray1 = outArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray2 = outArray2.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 32) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray1 || (alignment * 2) < sizeOfoutArray2) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray1 = new byte[alignment * 2]; + this.outArray2 = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle1 = GCHandle.Alloc(this.outArray1, GCHandleType.Pinned); + this.outHandle2 = GCHandle.Alloc(this.outArray2, 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* outArray1Ptr => Align((byte*)(outHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArray2Ptr => Align((byte*)(outHandle2.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle1.Free(); + outHandle2.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Ret1ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int Ret2ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int Op1ElementCount = Ret1ElementCount + Ret2ElementCount; + + private static Int64[] _data = new Int64[Op1ElementCount]; + + private DataTable _dataTable; + + public LoadPairVector64NonTemporal_Int64() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + _dataTable = new DataTable(_data, new Int64[Ret1ElementCount], new Int64[Ret2ElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var (value1, value2) = AdvSimd.Arm64.LoadPairVector64NonTemporal((Int64*)(_dataTable.inArray1Ptr)); + Unsafe.Write(_dataTable.outArray1Ptr, value1); + Unsafe.Write(_dataTable.outArray2Ptr, value2); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArray1Ptr, _dataTable.outArray2Ptr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.LoadPairVector64NonTemporal), new Type[] { typeof(Int64*) }) + .Invoke(null, new object[] { + Pointer.Box(_dataTable.inArray1Ptr, typeof(Int64*)) + }); + + var (value1, value2) = ((Vector64, Vector64))result; + + Unsafe.Write(_dataTable.outArray1Ptr, value1); + Unsafe.Write(_dataTable.outArray2Ptr, value2); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArray1Ptr, _dataTable.outArray2Ptr); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + Succeeded = false; + + try + { + RunBasicScenario_Load(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(void* firstOp, void* result1, void* result2, [CallerMemberName] string method = "") + { + Int64[] inArray = new Int64[Op1ElementCount]; + Int64[] outArray1 = new Int64[Ret1ElementCount]; + Int64[] outArray2 = new Int64[Ret2ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)(Unsafe.SizeOf() * Op1ElementCount)); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray1[0]), ref Unsafe.AsRef(result1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray2[0]), ref Unsafe.AsRef(result2), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray1, outArray2, method); + } + + private void ValidateResult(Int64[] firstOp, Int64[] firstResult, Int64[] secondResult, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (int i = 0; i < Op1ElementCount; i++) + { + if (firstOp[i] != Helpers.Concat(firstResult, secondResult, i)) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.LoadPairVector64NonTemporal)}(Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" firstResult: ({string.Join(", ", firstResult)})"); + TestLibrary.TestFramework.LogInformation($"secondResult: ({string.Join(", ", secondResult)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector64NonTemporal.SByte.cs b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector64NonTemporal.SByte.cs new file mode 100644 index 00000000000000..4322ef8bce1dad --- /dev/null +++ b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector64NonTemporal.SByte.cs @@ -0,0 +1,203 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Reflection; +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 LoadPairVector64NonTemporal_SByte() + { + var test = new LoadPairVector64NonTemporal_SByte(); + + if (test.IsSupported) + { + // Validates basic functionality works + test.RunBasicScenario_Load(); + + // Validates calling via reflection works + test.RunReflectionScenario_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 LoadPairVector64NonTemporal_SByte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray1; + private byte[] outArray2; + + private GCHandle inHandle1; + private GCHandle outHandle1; + private GCHandle outHandle2; + + private ulong alignment; + + public DataTable(SByte[] inArray1, SByte[] outArray1, SByte[] outArray2, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray1 = outArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray2 = outArray2.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 32) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray1 || (alignment * 2) < sizeOfoutArray2) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray1 = new byte[alignment * 2]; + this.outArray2 = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle1 = GCHandle.Alloc(this.outArray1, GCHandleType.Pinned); + this.outHandle2 = GCHandle.Alloc(this.outArray2, 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* outArray1Ptr => Align((byte*)(outHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArray2Ptr => Align((byte*)(outHandle2.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle1.Free(); + outHandle2.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Ret1ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int Ret2ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int Op1ElementCount = Ret1ElementCount + Ret2ElementCount; + + private static SByte[] _data = new SByte[Op1ElementCount]; + + private DataTable _dataTable; + + public LoadPairVector64NonTemporal_SByte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data, new SByte[Ret1ElementCount], new SByte[Ret2ElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var (value1, value2) = AdvSimd.Arm64.LoadPairVector64NonTemporal((SByte*)(_dataTable.inArray1Ptr)); + Unsafe.Write(_dataTable.outArray1Ptr, value1); + Unsafe.Write(_dataTable.outArray2Ptr, value2); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArray1Ptr, _dataTable.outArray2Ptr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.LoadPairVector64NonTemporal), new Type[] { typeof(SByte*) }) + .Invoke(null, new object[] { + Pointer.Box(_dataTable.inArray1Ptr, typeof(SByte*)) + }); + + var (value1, value2) = ((Vector64, Vector64))result; + + Unsafe.Write(_dataTable.outArray1Ptr, value1); + Unsafe.Write(_dataTable.outArray2Ptr, value2); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArray1Ptr, _dataTable.outArray2Ptr); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + Succeeded = false; + + try + { + RunBasicScenario_Load(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(void* firstOp, void* result1, void* result2, [CallerMemberName] string method = "") + { + SByte[] inArray = new SByte[Op1ElementCount]; + SByte[] outArray1 = new SByte[Ret1ElementCount]; + SByte[] outArray2 = new SByte[Ret2ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)(Unsafe.SizeOf() * Op1ElementCount)); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray1[0]), ref Unsafe.AsRef(result1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray2[0]), ref Unsafe.AsRef(result2), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray1, outArray2, method); + } + + private void ValidateResult(SByte[] firstOp, SByte[] firstResult, SByte[] secondResult, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (int i = 0; i < Op1ElementCount; i++) + { + if (firstOp[i] != Helpers.Concat(firstResult, secondResult, i)) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.LoadPairVector64NonTemporal)}(Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" firstResult: ({string.Join(", ", firstResult)})"); + TestLibrary.TestFramework.LogInformation($"secondResult: ({string.Join(", ", secondResult)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector64NonTemporal.Single.cs b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector64NonTemporal.Single.cs new file mode 100644 index 00000000000000..d3900c3e792431 --- /dev/null +++ b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector64NonTemporal.Single.cs @@ -0,0 +1,203 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Reflection; +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 LoadPairVector64NonTemporal_Single() + { + var test = new LoadPairVector64NonTemporal_Single(); + + if (test.IsSupported) + { + // Validates basic functionality works + test.RunBasicScenario_Load(); + + // Validates calling via reflection works + test.RunReflectionScenario_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 LoadPairVector64NonTemporal_Single + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray1; + private byte[] outArray2; + + private GCHandle inHandle1; + private GCHandle outHandle1; + private GCHandle outHandle2; + + private ulong alignment; + + public DataTable(Single[] inArray1, Single[] outArray1, Single[] outArray2, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray1 = outArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray2 = outArray2.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 32) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray1 || (alignment * 2) < sizeOfoutArray2) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray1 = new byte[alignment * 2]; + this.outArray2 = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle1 = GCHandle.Alloc(this.outArray1, GCHandleType.Pinned); + this.outHandle2 = GCHandle.Alloc(this.outArray2, 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* outArray1Ptr => Align((byte*)(outHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArray2Ptr => Align((byte*)(outHandle2.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle1.Free(); + outHandle2.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Ret1ElementCount = Unsafe.SizeOf>() / sizeof(Single); + private static readonly int Ret2ElementCount = Unsafe.SizeOf>() / sizeof(Single); + private static readonly int Op1ElementCount = Ret1ElementCount + Ret2ElementCount; + + private static Single[] _data = new Single[Op1ElementCount]; + + private DataTable _dataTable; + + public LoadPairVector64NonTemporal_Single() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetSingle(); } + _dataTable = new DataTable(_data, new Single[Ret1ElementCount], new Single[Ret2ElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var (value1, value2) = AdvSimd.Arm64.LoadPairVector64NonTemporal((Single*)(_dataTable.inArray1Ptr)); + Unsafe.Write(_dataTable.outArray1Ptr, value1); + Unsafe.Write(_dataTable.outArray2Ptr, value2); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArray1Ptr, _dataTable.outArray2Ptr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.LoadPairVector64NonTemporal), new Type[] { typeof(Single*) }) + .Invoke(null, new object[] { + Pointer.Box(_dataTable.inArray1Ptr, typeof(Single*)) + }); + + var (value1, value2) = ((Vector64, Vector64))result; + + Unsafe.Write(_dataTable.outArray1Ptr, value1); + Unsafe.Write(_dataTable.outArray2Ptr, value2); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArray1Ptr, _dataTable.outArray2Ptr); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + Succeeded = false; + + try + { + RunBasicScenario_Load(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(void* firstOp, void* result1, void* result2, [CallerMemberName] string method = "") + { + Single[] inArray = new Single[Op1ElementCount]; + Single[] outArray1 = new Single[Ret1ElementCount]; + Single[] outArray2 = new Single[Ret2ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)(Unsafe.SizeOf() * Op1ElementCount)); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray1[0]), ref Unsafe.AsRef(result1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray2[0]), ref Unsafe.AsRef(result2), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray1, outArray2, method); + } + + private void ValidateResult(Single[] firstOp, Single[] firstResult, Single[] secondResult, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (int i = 0; i < Op1ElementCount; i++) + { + if (BitConverter.SingleToInt32Bits(firstOp[i]) != BitConverter.SingleToInt32Bits(Helpers.Concat(firstResult, secondResult, i))) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.LoadPairVector64NonTemporal)}(Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" firstResult: ({string.Join(", ", firstResult)})"); + TestLibrary.TestFramework.LogInformation($"secondResult: ({string.Join(", ", secondResult)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector64NonTemporal.UInt16.cs b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector64NonTemporal.UInt16.cs new file mode 100644 index 00000000000000..44611934adee9a --- /dev/null +++ b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector64NonTemporal.UInt16.cs @@ -0,0 +1,203 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Reflection; +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 LoadPairVector64NonTemporal_UInt16() + { + var test = new LoadPairVector64NonTemporal_UInt16(); + + if (test.IsSupported) + { + // Validates basic functionality works + test.RunBasicScenario_Load(); + + // Validates calling via reflection works + test.RunReflectionScenario_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 LoadPairVector64NonTemporal_UInt16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray1; + private byte[] outArray2; + + private GCHandle inHandle1; + private GCHandle outHandle1; + private GCHandle outHandle2; + + private ulong alignment; + + public DataTable(UInt16[] inArray1, UInt16[] outArray1, UInt16[] outArray2, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray1 = outArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray2 = outArray2.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 32) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray1 || (alignment * 2) < sizeOfoutArray2) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray1 = new byte[alignment * 2]; + this.outArray2 = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle1 = GCHandle.Alloc(this.outArray1, GCHandleType.Pinned); + this.outHandle2 = GCHandle.Alloc(this.outArray2, 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* outArray1Ptr => Align((byte*)(outHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArray2Ptr => Align((byte*)(outHandle2.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle1.Free(); + outHandle2.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Ret1ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int Ret2ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int Op1ElementCount = Ret1ElementCount + Ret2ElementCount; + + private static UInt16[] _data = new UInt16[Op1ElementCount]; + + private DataTable _dataTable; + + public LoadPairVector64NonTemporal_UInt16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt16(); } + _dataTable = new DataTable(_data, new UInt16[Ret1ElementCount], new UInt16[Ret2ElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var (value1, value2) = AdvSimd.Arm64.LoadPairVector64NonTemporal((UInt16*)(_dataTable.inArray1Ptr)); + Unsafe.Write(_dataTable.outArray1Ptr, value1); + Unsafe.Write(_dataTable.outArray2Ptr, value2); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArray1Ptr, _dataTable.outArray2Ptr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.LoadPairVector64NonTemporal), new Type[] { typeof(UInt16*) }) + .Invoke(null, new object[] { + Pointer.Box(_dataTable.inArray1Ptr, typeof(UInt16*)) + }); + + var (value1, value2) = ((Vector64, Vector64))result; + + Unsafe.Write(_dataTable.outArray1Ptr, value1); + Unsafe.Write(_dataTable.outArray2Ptr, value2); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArray1Ptr, _dataTable.outArray2Ptr); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + Succeeded = false; + + try + { + RunBasicScenario_Load(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(void* firstOp, void* result1, void* result2, [CallerMemberName] string method = "") + { + UInt16[] inArray = new UInt16[Op1ElementCount]; + UInt16[] outArray1 = new UInt16[Ret1ElementCount]; + UInt16[] outArray2 = new UInt16[Ret2ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)(Unsafe.SizeOf() * Op1ElementCount)); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray1[0]), ref Unsafe.AsRef(result1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray2[0]), ref Unsafe.AsRef(result2), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray1, outArray2, method); + } + + private void ValidateResult(UInt16[] firstOp, UInt16[] firstResult, UInt16[] secondResult, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (int i = 0; i < Op1ElementCount; i++) + { + if (firstOp[i] != Helpers.Concat(firstResult, secondResult, i)) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.LoadPairVector64NonTemporal)}(Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" firstResult: ({string.Join(", ", firstResult)})"); + TestLibrary.TestFramework.LogInformation($"secondResult: ({string.Join(", ", secondResult)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector64NonTemporal.UInt32.cs b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector64NonTemporal.UInt32.cs new file mode 100644 index 00000000000000..deff5feca1ebae --- /dev/null +++ b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector64NonTemporal.UInt32.cs @@ -0,0 +1,203 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Reflection; +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 LoadPairVector64NonTemporal_UInt32() + { + var test = new LoadPairVector64NonTemporal_UInt32(); + + if (test.IsSupported) + { + // Validates basic functionality works + test.RunBasicScenario_Load(); + + // Validates calling via reflection works + test.RunReflectionScenario_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 LoadPairVector64NonTemporal_UInt32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray1; + private byte[] outArray2; + + private GCHandle inHandle1; + private GCHandle outHandle1; + private GCHandle outHandle2; + + private ulong alignment; + + public DataTable(UInt32[] inArray1, UInt32[] outArray1, UInt32[] outArray2, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray1 = outArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray2 = outArray2.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 32) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray1 || (alignment * 2) < sizeOfoutArray2) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray1 = new byte[alignment * 2]; + this.outArray2 = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle1 = GCHandle.Alloc(this.outArray1, GCHandleType.Pinned); + this.outHandle2 = GCHandle.Alloc(this.outArray2, 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* outArray1Ptr => Align((byte*)(outHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArray2Ptr => Align((byte*)(outHandle2.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle1.Free(); + outHandle2.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Ret1ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int Ret2ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int Op1ElementCount = Ret1ElementCount + Ret2ElementCount; + + private static UInt32[] _data = new UInt32[Op1ElementCount]; + + private DataTable _dataTable; + + public LoadPairVector64NonTemporal_UInt32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt32(); } + _dataTable = new DataTable(_data, new UInt32[Ret1ElementCount], new UInt32[Ret2ElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var (value1, value2) = AdvSimd.Arm64.LoadPairVector64NonTemporal((UInt32*)(_dataTable.inArray1Ptr)); + Unsafe.Write(_dataTable.outArray1Ptr, value1); + Unsafe.Write(_dataTable.outArray2Ptr, value2); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArray1Ptr, _dataTable.outArray2Ptr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.LoadPairVector64NonTemporal), new Type[] { typeof(UInt32*) }) + .Invoke(null, new object[] { + Pointer.Box(_dataTable.inArray1Ptr, typeof(UInt32*)) + }); + + var (value1, value2) = ((Vector64, Vector64))result; + + Unsafe.Write(_dataTable.outArray1Ptr, value1); + Unsafe.Write(_dataTable.outArray2Ptr, value2); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArray1Ptr, _dataTable.outArray2Ptr); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + Succeeded = false; + + try + { + RunBasicScenario_Load(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(void* firstOp, void* result1, void* result2, [CallerMemberName] string method = "") + { + UInt32[] inArray = new UInt32[Op1ElementCount]; + UInt32[] outArray1 = new UInt32[Ret1ElementCount]; + UInt32[] outArray2 = new UInt32[Ret2ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)(Unsafe.SizeOf() * Op1ElementCount)); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray1[0]), ref Unsafe.AsRef(result1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray2[0]), ref Unsafe.AsRef(result2), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray1, outArray2, method); + } + + private void ValidateResult(UInt32[] firstOp, UInt32[] firstResult, UInt32[] secondResult, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (int i = 0; i < Op1ElementCount; i++) + { + if (firstOp[i] != Helpers.Concat(firstResult, secondResult, i)) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.LoadPairVector64NonTemporal)}(Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" firstResult: ({string.Join(", ", firstResult)})"); + TestLibrary.TestFramework.LogInformation($"secondResult: ({string.Join(", ", secondResult)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector64NonTemporal.UInt64.cs b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector64NonTemporal.UInt64.cs new file mode 100644 index 00000000000000..de04027064efbd --- /dev/null +++ b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/LoadPairVector64NonTemporal.UInt64.cs @@ -0,0 +1,203 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Reflection; +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 LoadPairVector64NonTemporal_UInt64() + { + var test = new LoadPairVector64NonTemporal_UInt64(); + + if (test.IsSupported) + { + // Validates basic functionality works + test.RunBasicScenario_Load(); + + // Validates calling via reflection works + test.RunReflectionScenario_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 LoadPairVector64NonTemporal_UInt64 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray1; + private byte[] outArray2; + + private GCHandle inHandle1; + private GCHandle outHandle1; + private GCHandle outHandle2; + + private ulong alignment; + + public DataTable(UInt64[] inArray1, UInt64[] outArray1, UInt64[] outArray2, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray1 = outArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray2 = outArray2.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 32) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray1 || (alignment * 2) < sizeOfoutArray2) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray1 = new byte[alignment * 2]; + this.outArray2 = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle1 = GCHandle.Alloc(this.outArray1, GCHandleType.Pinned); + this.outHandle2 = GCHandle.Alloc(this.outArray2, 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* outArray1Ptr => Align((byte*)(outHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArray2Ptr => Align((byte*)(outHandle2.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle1.Free(); + outHandle2.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Ret1ElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + private static readonly int Ret2ElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + private static readonly int Op1ElementCount = Ret1ElementCount + Ret2ElementCount; + + private static UInt64[] _data = new UInt64[Op1ElementCount]; + + private DataTable _dataTable; + + public LoadPairVector64NonTemporal_UInt64() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt64(); } + _dataTable = new DataTable(_data, new UInt64[Ret1ElementCount], new UInt64[Ret2ElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var (value1, value2) = AdvSimd.Arm64.LoadPairVector64NonTemporal((UInt64*)(_dataTable.inArray1Ptr)); + Unsafe.Write(_dataTable.outArray1Ptr, value1); + Unsafe.Write(_dataTable.outArray2Ptr, value2); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArray1Ptr, _dataTable.outArray2Ptr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.LoadPairVector64NonTemporal), new Type[] { typeof(UInt64*) }) + .Invoke(null, new object[] { + Pointer.Box(_dataTable.inArray1Ptr, typeof(UInt64*)) + }); + + var (value1, value2) = ((Vector64, Vector64))result; + + Unsafe.Write(_dataTable.outArray1Ptr, value1); + Unsafe.Write(_dataTable.outArray2Ptr, value2); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArray1Ptr, _dataTable.outArray2Ptr); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + Succeeded = false; + + try + { + RunBasicScenario_Load(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(void* firstOp, void* result1, void* result2, [CallerMemberName] string method = "") + { + UInt64[] inArray = new UInt64[Op1ElementCount]; + UInt64[] outArray1 = new UInt64[Ret1ElementCount]; + UInt64[] outArray2 = new UInt64[Ret2ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)(Unsafe.SizeOf() * Op1ElementCount)); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray1[0]), ref Unsafe.AsRef(result1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray2[0]), ref Unsafe.AsRef(result2), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray1, outArray2, method); + } + + private void ValidateResult(UInt64[] firstOp, UInt64[] firstResult, UInt64[] secondResult, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (int i = 0; i < Op1ElementCount; i++) + { + if (firstOp[i] != Helpers.Concat(firstResult, secondResult, i)) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.LoadPairVector64NonTemporal)}(Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" firstResult: ({string.Join(", ", firstResult)})"); + TestLibrary.TestFramework.LogInformation($"secondResult: ({string.Join(", ", secondResult)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/Program.AdvSimd.Arm64_Part2.cs b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/Program.AdvSimd.Arm64_Part2.cs index 29788e0053f174..f34c72ddcca819 100644 --- a/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/Program.AdvSimd.Arm64_Part2.cs +++ b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/Program.AdvSimd.Arm64_Part2.cs @@ -49,6 +49,52 @@ static Program() ["LoadAndReplicateToVector128.Double"] = LoadAndReplicateToVector128_Double, ["LoadAndReplicateToVector128.Int64"] = LoadAndReplicateToVector128_Int64, ["LoadAndReplicateToVector128.UInt64"] = LoadAndReplicateToVector128_UInt64, + ["LoadPairScalarVector64.Int32"] = LoadPairScalarVector64_Int32, + ["LoadPairScalarVector64.Single"] = LoadPairScalarVector64_Single, + ["LoadPairScalarVector64.UInt32"] = LoadPairScalarVector64_UInt32, + ["LoadPairScalarVector64NonTemporal.Int32"] = LoadPairScalarVector64NonTemporal_Int32, + ["LoadPairScalarVector64NonTemporal.Single"] = LoadPairScalarVector64NonTemporal_Single, + ["LoadPairScalarVector64NonTemporal.UInt32"] = LoadPairScalarVector64NonTemporal_UInt32, + ["LoadPairVector64.Byte"] = LoadPairVector64_Byte, + ["LoadPairVector64.Double"] = LoadPairVector64_Double, + ["LoadPairVector64.Int16"] = LoadPairVector64_Int16, + ["LoadPairVector64.Int32"] = LoadPairVector64_Int32, + ["LoadPairVector64.Int64"] = LoadPairVector64_Int64, + ["LoadPairVector64.SByte"] = LoadPairVector64_SByte, + ["LoadPairVector64.Single"] = LoadPairVector64_Single, + ["LoadPairVector64.UInt16"] = LoadPairVector64_UInt16, + ["LoadPairVector64.UInt32"] = LoadPairVector64_UInt32, + ["LoadPairVector64.UInt64"] = LoadPairVector64_UInt64, + ["LoadPairVector64NonTemporal.Byte"] = LoadPairVector64NonTemporal_Byte, + ["LoadPairVector64NonTemporal.Double"] = LoadPairVector64NonTemporal_Double, + ["LoadPairVector64NonTemporal.Int16"] = LoadPairVector64NonTemporal_Int16, + ["LoadPairVector64NonTemporal.Int32"] = LoadPairVector64NonTemporal_Int32, + ["LoadPairVector64NonTemporal.Int64"] = LoadPairVector64NonTemporal_Int64, + ["LoadPairVector64NonTemporal.SByte"] = LoadPairVector64NonTemporal_SByte, + ["LoadPairVector64NonTemporal.Single"] = LoadPairVector64NonTemporal_Single, + ["LoadPairVector64NonTemporal.UInt16"] = LoadPairVector64NonTemporal_UInt16, + ["LoadPairVector64NonTemporal.UInt32"] = LoadPairVector64NonTemporal_UInt32, + ["LoadPairVector64NonTemporal.UInt64"] = LoadPairVector64NonTemporal_UInt64, + ["LoadPairVector128.Byte"] = LoadPairVector128_Byte, + ["LoadPairVector128.Double"] = LoadPairVector128_Double, + ["LoadPairVector128.Int16"] = LoadPairVector128_Int16, + ["LoadPairVector128.Int32"] = LoadPairVector128_Int32, + ["LoadPairVector128.Int64"] = LoadPairVector128_Int64, + ["LoadPairVector128.SByte"] = LoadPairVector128_SByte, + ["LoadPairVector128.Single"] = LoadPairVector128_Single, + ["LoadPairVector128.UInt16"] = LoadPairVector128_UInt16, + ["LoadPairVector128.UInt32"] = LoadPairVector128_UInt32, + ["LoadPairVector128.UInt64"] = LoadPairVector128_UInt64, + ["LoadPairVector128NonTemporal.Byte"] = LoadPairVector128NonTemporal_Byte, + ["LoadPairVector128NonTemporal.Double"] = LoadPairVector128NonTemporal_Double, + ["LoadPairVector128NonTemporal.Int16"] = LoadPairVector128NonTemporal_Int16, + ["LoadPairVector128NonTemporal.Int32"] = LoadPairVector128NonTemporal_Int32, + ["LoadPairVector128NonTemporal.Int64"] = LoadPairVector128NonTemporal_Int64, + ["LoadPairVector128NonTemporal.SByte"] = LoadPairVector128NonTemporal_SByte, + ["LoadPairVector128NonTemporal.Single"] = LoadPairVector128NonTemporal_Single, + ["LoadPairVector128NonTemporal.UInt16"] = LoadPairVector128NonTemporal_UInt16, + ["LoadPairVector128NonTemporal.UInt32"] = LoadPairVector128NonTemporal_UInt32, + ["LoadPairVector128NonTemporal.UInt64"] = LoadPairVector128NonTemporal_UInt64, ["Max.Vector128.Double"] = Max_Vector128_Double, ["MaxAcross.Vector64.Byte"] = MaxAcross_Vector64_Byte, ["MaxAcross.Vector64.Int16"] = MaxAcross_Vector64_Int16, @@ -65,52 +111,6 @@ static Program() ["MaxNumberAcross.Vector128.Single"] = MaxNumberAcross_Vector128_Single, ["MaxNumberPairwise.Vector64.Single"] = MaxNumberPairwise_Vector64_Single, ["MaxNumberPairwise.Vector128.Double"] = MaxNumberPairwise_Vector128_Double, - ["MaxNumberPairwise.Vector128.Single"] = MaxNumberPairwise_Vector128_Single, - ["MaxNumberPairwiseScalar.Vector64.Single"] = MaxNumberPairwiseScalar_Vector64_Single, - ["MaxNumberPairwiseScalar.Vector128.Double"] = MaxNumberPairwiseScalar_Vector128_Double, - ["MaxPairwise.Vector128.Byte"] = MaxPairwise_Vector128_Byte, - ["MaxPairwise.Vector128.Double"] = MaxPairwise_Vector128_Double, - ["MaxPairwise.Vector128.Int16"] = MaxPairwise_Vector128_Int16, - ["MaxPairwise.Vector128.Int32"] = MaxPairwise_Vector128_Int32, - ["MaxPairwise.Vector128.SByte"] = MaxPairwise_Vector128_SByte, - ["MaxPairwise.Vector128.Single"] = MaxPairwise_Vector128_Single, - ["MaxPairwise.Vector128.UInt16"] = MaxPairwise_Vector128_UInt16, - ["MaxPairwise.Vector128.UInt32"] = MaxPairwise_Vector128_UInt32, - ["MaxPairwiseScalar.Vector64.Single"] = MaxPairwiseScalar_Vector64_Single, - ["MaxPairwiseScalar.Vector128.Double"] = MaxPairwiseScalar_Vector128_Double, - ["MaxScalar.Vector64.Double"] = MaxScalar_Vector64_Double, - ["MaxScalar.Vector64.Single"] = MaxScalar_Vector64_Single, - ["Min.Vector128.Double"] = Min_Vector128_Double, - ["MinAcross.Vector64.Byte"] = MinAcross_Vector64_Byte, - ["MinAcross.Vector64.Int16"] = MinAcross_Vector64_Int16, - ["MinAcross.Vector64.SByte"] = MinAcross_Vector64_SByte, - ["MinAcross.Vector64.UInt16"] = MinAcross_Vector64_UInt16, - ["MinAcross.Vector128.Byte"] = MinAcross_Vector128_Byte, - ["MinAcross.Vector128.Int16"] = MinAcross_Vector128_Int16, - ["MinAcross.Vector128.Int32"] = MinAcross_Vector128_Int32, - ["MinAcross.Vector128.SByte"] = MinAcross_Vector128_SByte, - ["MinAcross.Vector128.Single"] = MinAcross_Vector128_Single, - ["MinAcross.Vector128.UInt16"] = MinAcross_Vector128_UInt16, - ["MinAcross.Vector128.UInt32"] = MinAcross_Vector128_UInt32, - ["MinNumber.Vector128.Double"] = MinNumber_Vector128_Double, - ["MinNumberAcross.Vector128.Single"] = MinNumberAcross_Vector128_Single, - ["MinNumberPairwise.Vector64.Single"] = MinNumberPairwise_Vector64_Single, - ["MinNumberPairwise.Vector128.Double"] = MinNumberPairwise_Vector128_Double, - ["MinNumberPairwise.Vector128.Single"] = MinNumberPairwise_Vector128_Single, - ["MinNumberPairwiseScalar.Vector64.Single"] = MinNumberPairwiseScalar_Vector64_Single, - ["MinNumberPairwiseScalar.Vector128.Double"] = MinNumberPairwiseScalar_Vector128_Double, - ["MinPairwise.Vector128.Byte"] = MinPairwise_Vector128_Byte, - ["MinPairwise.Vector128.Double"] = MinPairwise_Vector128_Double, - ["MinPairwise.Vector128.Int16"] = MinPairwise_Vector128_Int16, - ["MinPairwise.Vector128.Int32"] = MinPairwise_Vector128_Int32, - ["MinPairwise.Vector128.SByte"] = MinPairwise_Vector128_SByte, - ["MinPairwise.Vector128.Single"] = MinPairwise_Vector128_Single, - ["MinPairwise.Vector128.UInt16"] = MinPairwise_Vector128_UInt16, - ["MinPairwise.Vector128.UInt32"] = MinPairwise_Vector128_UInt32, - ["MinPairwiseScalar.Vector64.Single"] = MinPairwiseScalar_Vector64_Single, - ["MinPairwiseScalar.Vector128.Double"] = MinPairwiseScalar_Vector128_Double, - ["MinScalar.Vector64.Double"] = MinScalar_Vector64_Double, - ["MinScalar.Vector64.Single"] = MinScalar_Vector64_Single, }; } } diff --git a/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/Program.AdvSimd.Arm64_Part3.cs b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/Program.AdvSimd.Arm64_Part3.cs index c7c238a050d7bb..77c36bd700a5d9 100644 --- a/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/Program.AdvSimd.Arm64_Part3.cs +++ b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/Program.AdvSimd.Arm64_Part3.cs @@ -11,6 +11,52 @@ public static partial class Program static Program() { TestList = new Dictionary() { + ["MaxNumberPairwise.Vector128.Single"] = MaxNumberPairwise_Vector128_Single, + ["MaxNumberPairwiseScalar.Vector64.Single"] = MaxNumberPairwiseScalar_Vector64_Single, + ["MaxNumberPairwiseScalar.Vector128.Double"] = MaxNumberPairwiseScalar_Vector128_Double, + ["MaxPairwise.Vector128.Byte"] = MaxPairwise_Vector128_Byte, + ["MaxPairwise.Vector128.Double"] = MaxPairwise_Vector128_Double, + ["MaxPairwise.Vector128.Int16"] = MaxPairwise_Vector128_Int16, + ["MaxPairwise.Vector128.Int32"] = MaxPairwise_Vector128_Int32, + ["MaxPairwise.Vector128.SByte"] = MaxPairwise_Vector128_SByte, + ["MaxPairwise.Vector128.Single"] = MaxPairwise_Vector128_Single, + ["MaxPairwise.Vector128.UInt16"] = MaxPairwise_Vector128_UInt16, + ["MaxPairwise.Vector128.UInt32"] = MaxPairwise_Vector128_UInt32, + ["MaxPairwiseScalar.Vector64.Single"] = MaxPairwiseScalar_Vector64_Single, + ["MaxPairwiseScalar.Vector128.Double"] = MaxPairwiseScalar_Vector128_Double, + ["MaxScalar.Vector64.Double"] = MaxScalar_Vector64_Double, + ["MaxScalar.Vector64.Single"] = MaxScalar_Vector64_Single, + ["Min.Vector128.Double"] = Min_Vector128_Double, + ["MinAcross.Vector64.Byte"] = MinAcross_Vector64_Byte, + ["MinAcross.Vector64.Int16"] = MinAcross_Vector64_Int16, + ["MinAcross.Vector64.SByte"] = MinAcross_Vector64_SByte, + ["MinAcross.Vector64.UInt16"] = MinAcross_Vector64_UInt16, + ["MinAcross.Vector128.Byte"] = MinAcross_Vector128_Byte, + ["MinAcross.Vector128.Int16"] = MinAcross_Vector128_Int16, + ["MinAcross.Vector128.Int32"] = MinAcross_Vector128_Int32, + ["MinAcross.Vector128.SByte"] = MinAcross_Vector128_SByte, + ["MinAcross.Vector128.Single"] = MinAcross_Vector128_Single, + ["MinAcross.Vector128.UInt16"] = MinAcross_Vector128_UInt16, + ["MinAcross.Vector128.UInt32"] = MinAcross_Vector128_UInt32, + ["MinNumber.Vector128.Double"] = MinNumber_Vector128_Double, + ["MinNumberAcross.Vector128.Single"] = MinNumberAcross_Vector128_Single, + ["MinNumberPairwise.Vector64.Single"] = MinNumberPairwise_Vector64_Single, + ["MinNumberPairwise.Vector128.Double"] = MinNumberPairwise_Vector128_Double, + ["MinNumberPairwise.Vector128.Single"] = MinNumberPairwise_Vector128_Single, + ["MinNumberPairwiseScalar.Vector64.Single"] = MinNumberPairwiseScalar_Vector64_Single, + ["MinNumberPairwiseScalar.Vector128.Double"] = MinNumberPairwiseScalar_Vector128_Double, + ["MinPairwise.Vector128.Byte"] = MinPairwise_Vector128_Byte, + ["MinPairwise.Vector128.Double"] = MinPairwise_Vector128_Double, + ["MinPairwise.Vector128.Int16"] = MinPairwise_Vector128_Int16, + ["MinPairwise.Vector128.Int32"] = MinPairwise_Vector128_Int32, + ["MinPairwise.Vector128.SByte"] = MinPairwise_Vector128_SByte, + ["MinPairwise.Vector128.Single"] = MinPairwise_Vector128_Single, + ["MinPairwise.Vector128.UInt16"] = MinPairwise_Vector128_UInt16, + ["MinPairwise.Vector128.UInt32"] = MinPairwise_Vector128_UInt32, + ["MinPairwiseScalar.Vector64.Single"] = MinPairwiseScalar_Vector64_Single, + ["MinPairwiseScalar.Vector128.Double"] = MinPairwiseScalar_Vector128_Double, + ["MinScalar.Vector64.Double"] = MinScalar_Vector64_Double, + ["MinScalar.Vector64.Single"] = MinScalar_Vector64_Single, ["Multiply.Vector128.Double"] = Multiply_Vector128_Double, ["MultiplyByScalar.Vector128.Double"] = MultiplyByScalar_Vector128_Double, ["MultiplyBySelectedScalar.Vector128.Double.Vector128.Double.1"] = MultiplyBySelectedScalar_Vector128_Double_Vector128_Double_1, @@ -65,52 +111,6 @@ static Program() ["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, - ["ReverseElementBits.Vector64.SByte"] = ReverseElementBits_Vector64_SByte, - ["RoundAwayFromZero.Vector128.Double"] = RoundAwayFromZero_Vector128_Double, - ["RoundToNearest.Vector128.Double"] = RoundToNearest_Vector128_Double, - ["RoundToNegativeInfinity.Vector128.Double"] = RoundToNegativeInfinity_Vector128_Double, - ["RoundToPositiveInfinity.Vector128.Double"] = RoundToPositiveInfinity_Vector128_Double, - ["RoundToZero.Vector128.Double"] = RoundToZero_Vector128_Double, - ["ShiftArithmeticRoundedSaturateScalar.Vector64.Int16"] = ShiftArithmeticRoundedSaturateScalar_Vector64_Int16, - ["ShiftArithmeticRoundedSaturateScalar.Vector64.Int32"] = ShiftArithmeticRoundedSaturateScalar_Vector64_Int32, - ["ShiftArithmeticRoundedSaturateScalar.Vector64.SByte"] = ShiftArithmeticRoundedSaturateScalar_Vector64_SByte, - ["ShiftArithmeticSaturateScalar.Vector64.Int16"] = ShiftArithmeticSaturateScalar_Vector64_Int16, - ["ShiftArithmeticSaturateScalar.Vector64.Int32"] = ShiftArithmeticSaturateScalar_Vector64_Int32, - ["ShiftArithmeticSaturateScalar.Vector64.SByte"] = ShiftArithmeticSaturateScalar_Vector64_SByte, - ["ShiftLeftLogicalSaturateScalar.Vector64.Byte.7"] = ShiftLeftLogicalSaturateScalar_Vector64_Byte_7, - ["ShiftLeftLogicalSaturateScalar.Vector64.Int16.15"] = ShiftLeftLogicalSaturateScalar_Vector64_Int16_15, - ["ShiftLeftLogicalSaturateScalar.Vector64.Int32.31"] = ShiftLeftLogicalSaturateScalar_Vector64_Int32_31, - ["ShiftLeftLogicalSaturateScalar.Vector64.SByte.1"] = ShiftLeftLogicalSaturateScalar_Vector64_SByte_1, - ["ShiftLeftLogicalSaturateScalar.Vector64.UInt16.1"] = ShiftLeftLogicalSaturateScalar_Vector64_UInt16_1, - ["ShiftLeftLogicalSaturateScalar.Vector64.UInt32.1"] = ShiftLeftLogicalSaturateScalar_Vector64_UInt32_1, - ["ShiftLeftLogicalSaturateUnsignedScalar.Vector64.Int16.5"] = ShiftLeftLogicalSaturateUnsignedScalar_Vector64_Int16_5, - ["ShiftLeftLogicalSaturateUnsignedScalar.Vector64.Int32.7"] = ShiftLeftLogicalSaturateUnsignedScalar_Vector64_Int32_7, - ["ShiftLeftLogicalSaturateUnsignedScalar.Vector64.SByte.3"] = ShiftLeftLogicalSaturateUnsignedScalar_Vector64_SByte_3, - ["ShiftLogicalRoundedSaturateScalar.Vector64.Byte"] = ShiftLogicalRoundedSaturateScalar_Vector64_Byte, - ["ShiftLogicalRoundedSaturateScalar.Vector64.Int16"] = ShiftLogicalRoundedSaturateScalar_Vector64_Int16, - ["ShiftLogicalRoundedSaturateScalar.Vector64.Int32"] = ShiftLogicalRoundedSaturateScalar_Vector64_Int32, - ["ShiftLogicalRoundedSaturateScalar.Vector64.SByte"] = ShiftLogicalRoundedSaturateScalar_Vector64_SByte, - ["ShiftLogicalRoundedSaturateScalar.Vector64.UInt16"] = ShiftLogicalRoundedSaturateScalar_Vector64_UInt16, - ["ShiftLogicalRoundedSaturateScalar.Vector64.UInt32"] = ShiftLogicalRoundedSaturateScalar_Vector64_UInt32, - ["ShiftLogicalSaturateScalar.Vector64.Byte"] = ShiftLogicalSaturateScalar_Vector64_Byte, - ["ShiftLogicalSaturateScalar.Vector64.Int16"] = ShiftLogicalSaturateScalar_Vector64_Int16, - ["ShiftLogicalSaturateScalar.Vector64.Int32"] = ShiftLogicalSaturateScalar_Vector64_Int32, - ["ShiftLogicalSaturateScalar.Vector64.SByte"] = ShiftLogicalSaturateScalar_Vector64_SByte, }; } } diff --git a/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/Program.AdvSimd.Arm64_Part4.cs b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/Program.AdvSimd.Arm64_Part4.cs index af2a7dcb3c8a06..7f93b00e0ba06f 100644 --- a/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/Program.AdvSimd.Arm64_Part4.cs +++ b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/Program.AdvSimd.Arm64_Part4.cs @@ -11,6 +11,52 @@ public static partial class Program static Program() { TestList = new Dictionary() { + ["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, + ["ReverseElementBits.Vector64.SByte"] = ReverseElementBits_Vector64_SByte, + ["RoundAwayFromZero.Vector128.Double"] = RoundAwayFromZero_Vector128_Double, + ["RoundToNearest.Vector128.Double"] = RoundToNearest_Vector128_Double, + ["RoundToNegativeInfinity.Vector128.Double"] = RoundToNegativeInfinity_Vector128_Double, + ["RoundToPositiveInfinity.Vector128.Double"] = RoundToPositiveInfinity_Vector128_Double, + ["RoundToZero.Vector128.Double"] = RoundToZero_Vector128_Double, + ["ShiftArithmeticRoundedSaturateScalar.Vector64.Int16"] = ShiftArithmeticRoundedSaturateScalar_Vector64_Int16, + ["ShiftArithmeticRoundedSaturateScalar.Vector64.Int32"] = ShiftArithmeticRoundedSaturateScalar_Vector64_Int32, + ["ShiftArithmeticRoundedSaturateScalar.Vector64.SByte"] = ShiftArithmeticRoundedSaturateScalar_Vector64_SByte, + ["ShiftArithmeticSaturateScalar.Vector64.Int16"] = ShiftArithmeticSaturateScalar_Vector64_Int16, + ["ShiftArithmeticSaturateScalar.Vector64.Int32"] = ShiftArithmeticSaturateScalar_Vector64_Int32, + ["ShiftArithmeticSaturateScalar.Vector64.SByte"] = ShiftArithmeticSaturateScalar_Vector64_SByte, + ["ShiftLeftLogicalSaturateScalar.Vector64.Byte.7"] = ShiftLeftLogicalSaturateScalar_Vector64_Byte_7, + ["ShiftLeftLogicalSaturateScalar.Vector64.Int16.15"] = ShiftLeftLogicalSaturateScalar_Vector64_Int16_15, + ["ShiftLeftLogicalSaturateScalar.Vector64.Int32.31"] = ShiftLeftLogicalSaturateScalar_Vector64_Int32_31, + ["ShiftLeftLogicalSaturateScalar.Vector64.SByte.1"] = ShiftLeftLogicalSaturateScalar_Vector64_SByte_1, + ["ShiftLeftLogicalSaturateScalar.Vector64.UInt16.1"] = ShiftLeftLogicalSaturateScalar_Vector64_UInt16_1, + ["ShiftLeftLogicalSaturateScalar.Vector64.UInt32.1"] = ShiftLeftLogicalSaturateScalar_Vector64_UInt32_1, + ["ShiftLeftLogicalSaturateUnsignedScalar.Vector64.Int16.5"] = ShiftLeftLogicalSaturateUnsignedScalar_Vector64_Int16_5, + ["ShiftLeftLogicalSaturateUnsignedScalar.Vector64.Int32.7"] = ShiftLeftLogicalSaturateUnsignedScalar_Vector64_Int32_7, + ["ShiftLeftLogicalSaturateUnsignedScalar.Vector64.SByte.3"] = ShiftLeftLogicalSaturateUnsignedScalar_Vector64_SByte_3, + ["ShiftLogicalRoundedSaturateScalar.Vector64.Byte"] = ShiftLogicalRoundedSaturateScalar_Vector64_Byte, + ["ShiftLogicalRoundedSaturateScalar.Vector64.Int16"] = ShiftLogicalRoundedSaturateScalar_Vector64_Int16, + ["ShiftLogicalRoundedSaturateScalar.Vector64.Int32"] = ShiftLogicalRoundedSaturateScalar_Vector64_Int32, + ["ShiftLogicalRoundedSaturateScalar.Vector64.SByte"] = ShiftLogicalRoundedSaturateScalar_Vector64_SByte, + ["ShiftLogicalRoundedSaturateScalar.Vector64.UInt16"] = ShiftLogicalRoundedSaturateScalar_Vector64_UInt16, + ["ShiftLogicalRoundedSaturateScalar.Vector64.UInt32"] = ShiftLogicalRoundedSaturateScalar_Vector64_UInt32, + ["ShiftLogicalSaturateScalar.Vector64.Byte"] = ShiftLogicalSaturateScalar_Vector64_Byte, + ["ShiftLogicalSaturateScalar.Vector64.Int16"] = ShiftLogicalSaturateScalar_Vector64_Int16, + ["ShiftLogicalSaturateScalar.Vector64.Int32"] = ShiftLogicalSaturateScalar_Vector64_Int32, + ["ShiftLogicalSaturateScalar.Vector64.SByte"] = ShiftLogicalSaturateScalar_Vector64_SByte, ["ShiftLogicalSaturateScalar.Vector64.UInt16"] = ShiftLogicalSaturateScalar_Vector64_UInt16, ["ShiftLogicalSaturateScalar.Vector64.UInt32"] = ShiftLogicalSaturateScalar_Vector64_UInt32, ["ShiftRightArithmeticNarrowingSaturateScalar.Vector64.Int16.16"] = ShiftRightArithmeticNarrowingSaturateScalar_Vector64_Int16_16, @@ -65,52 +111,6 @@ static Program() ["StorePairScalar.Vector64.UInt32"] = StorePairScalar_Vector64_UInt32, ["StorePairScalarNonTemporal.Vector64.Int32"] = StorePairScalarNonTemporal_Vector64_Int32, ["StorePairScalarNonTemporal.Vector64.Single"] = StorePairScalarNonTemporal_Vector64_Single, - ["StorePairScalarNonTemporal.Vector64.UInt32"] = StorePairScalarNonTemporal_Vector64_UInt32, - ["StorePairNonTemporal.Vector64.Byte"] = StorePairNonTemporal_Vector64_Byte, - ["StorePairNonTemporal.Vector64.Double"] = StorePairNonTemporal_Vector64_Double, - ["StorePairNonTemporal.Vector64.Int16"] = StorePairNonTemporal_Vector64_Int16, - ["StorePairNonTemporal.Vector64.Int32"] = StorePairNonTemporal_Vector64_Int32, - ["StorePairNonTemporal.Vector64.Int64"] = StorePairNonTemporal_Vector64_Int64, - ["StorePairNonTemporal.Vector64.SByte"] = StorePairNonTemporal_Vector64_SByte, - ["StorePairNonTemporal.Vector64.Single"] = StorePairNonTemporal_Vector64_Single, - ["StorePairNonTemporal.Vector64.UInt16"] = StorePairNonTemporal_Vector64_UInt16, - ["StorePairNonTemporal.Vector64.UInt32"] = StorePairNonTemporal_Vector64_UInt32, - ["StorePairNonTemporal.Vector64.UInt64"] = StorePairNonTemporal_Vector64_UInt64, - ["StorePairNonTemporal.Vector128.Byte"] = StorePairNonTemporal_Vector128_Byte, - ["StorePairNonTemporal.Vector128.Double"] = StorePairNonTemporal_Vector128_Double, - ["StorePairNonTemporal.Vector128.Int16"] = StorePairNonTemporal_Vector128_Int16, - ["StorePairNonTemporal.Vector128.Int32"] = StorePairNonTemporal_Vector128_Int32, - ["StorePairNonTemporal.Vector128.Int64"] = StorePairNonTemporal_Vector128_Int64, - ["StorePairNonTemporal.Vector128.SByte"] = StorePairNonTemporal_Vector128_SByte, - ["StorePairNonTemporal.Vector128.Single"] = StorePairNonTemporal_Vector128_Single, - ["StorePairNonTemporal.Vector128.UInt16"] = StorePairNonTemporal_Vector128_UInt16, - ["StorePairNonTemporal.Vector128.UInt32"] = StorePairNonTemporal_Vector128_UInt32, - ["StorePairNonTemporal.Vector128.UInt64"] = StorePairNonTemporal_Vector128_UInt64, - ["Subtract.Vector128.Double"] = Subtract_Vector128_Double, - ["SubtractSaturateScalar.Vector64.Byte"] = SubtractSaturateScalar_Vector64_Byte, - ["SubtractSaturateScalar.Vector64.Int16"] = SubtractSaturateScalar_Vector64_Int16, - ["SubtractSaturateScalar.Vector64.Int32"] = SubtractSaturateScalar_Vector64_Int32, - ["SubtractSaturateScalar.Vector64.SByte"] = SubtractSaturateScalar_Vector64_SByte, - ["SubtractSaturateScalar.Vector64.UInt16"] = SubtractSaturateScalar_Vector64_UInt16, - ["SubtractSaturateScalar.Vector64.UInt32"] = SubtractSaturateScalar_Vector64_UInt32, - ["TransposeEven.Vector64.Byte"] = TransposeEven_Vector64_Byte, - ["TransposeEven.Vector64.Int16"] = TransposeEven_Vector64_Int16, - ["TransposeEven.Vector64.Int32"] = TransposeEven_Vector64_Int32, - ["TransposeEven.Vector64.SByte"] = TransposeEven_Vector64_SByte, - ["TransposeEven.Vector64.Single"] = TransposeEven_Vector64_Single, - ["TransposeEven.Vector64.UInt16"] = TransposeEven_Vector64_UInt16, - ["TransposeEven.Vector64.UInt32"] = TransposeEven_Vector64_UInt32, - ["TransposeEven.Vector128.Byte"] = TransposeEven_Vector128_Byte, - ["TransposeEven.Vector128.Double"] = TransposeEven_Vector128_Double, - ["TransposeEven.Vector128.Int16"] = TransposeEven_Vector128_Int16, - ["TransposeEven.Vector128.Int32"] = TransposeEven_Vector128_Int32, - ["TransposeEven.Vector128.Int64"] = TransposeEven_Vector128_Int64, - ["TransposeEven.Vector128.SByte"] = TransposeEven_Vector128_SByte, - ["TransposeEven.Vector128.Single"] = TransposeEven_Vector128_Single, - ["TransposeEven.Vector128.UInt16"] = TransposeEven_Vector128_UInt16, - ["TransposeEven.Vector128.UInt32"] = TransposeEven_Vector128_UInt32, - ["TransposeEven.Vector128.UInt64"] = TransposeEven_Vector128_UInt64, - ["TransposeOdd.Vector64.Byte"] = TransposeOdd_Vector64_Byte, }; } } diff --git a/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/Program.AdvSimd.Arm64_Part5.cs b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/Program.AdvSimd.Arm64_Part5.cs index ce885756d0e364..13cb36890d5616 100644 --- a/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/Program.AdvSimd.Arm64_Part5.cs +++ b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/Program.AdvSimd.Arm64_Part5.cs @@ -11,6 +11,52 @@ public static partial class Program static Program() { TestList = new Dictionary() { + ["StorePairScalarNonTemporal.Vector64.UInt32"] = StorePairScalarNonTemporal_Vector64_UInt32, + ["StorePairNonTemporal.Vector64.Byte"] = StorePairNonTemporal_Vector64_Byte, + ["StorePairNonTemporal.Vector64.Double"] = StorePairNonTemporal_Vector64_Double, + ["StorePairNonTemporal.Vector64.Int16"] = StorePairNonTemporal_Vector64_Int16, + ["StorePairNonTemporal.Vector64.Int32"] = StorePairNonTemporal_Vector64_Int32, + ["StorePairNonTemporal.Vector64.Int64"] = StorePairNonTemporal_Vector64_Int64, + ["StorePairNonTemporal.Vector64.SByte"] = StorePairNonTemporal_Vector64_SByte, + ["StorePairNonTemporal.Vector64.Single"] = StorePairNonTemporal_Vector64_Single, + ["StorePairNonTemporal.Vector64.UInt16"] = StorePairNonTemporal_Vector64_UInt16, + ["StorePairNonTemporal.Vector64.UInt32"] = StorePairNonTemporal_Vector64_UInt32, + ["StorePairNonTemporal.Vector64.UInt64"] = StorePairNonTemporal_Vector64_UInt64, + ["StorePairNonTemporal.Vector128.Byte"] = StorePairNonTemporal_Vector128_Byte, + ["StorePairNonTemporal.Vector128.Double"] = StorePairNonTemporal_Vector128_Double, + ["StorePairNonTemporal.Vector128.Int16"] = StorePairNonTemporal_Vector128_Int16, + ["StorePairNonTemporal.Vector128.Int32"] = StorePairNonTemporal_Vector128_Int32, + ["StorePairNonTemporal.Vector128.Int64"] = StorePairNonTemporal_Vector128_Int64, + ["StorePairNonTemporal.Vector128.SByte"] = StorePairNonTemporal_Vector128_SByte, + ["StorePairNonTemporal.Vector128.Single"] = StorePairNonTemporal_Vector128_Single, + ["StorePairNonTemporal.Vector128.UInt16"] = StorePairNonTemporal_Vector128_UInt16, + ["StorePairNonTemporal.Vector128.UInt32"] = StorePairNonTemporal_Vector128_UInt32, + ["StorePairNonTemporal.Vector128.UInt64"] = StorePairNonTemporal_Vector128_UInt64, + ["Subtract.Vector128.Double"] = Subtract_Vector128_Double, + ["SubtractSaturateScalar.Vector64.Byte"] = SubtractSaturateScalar_Vector64_Byte, + ["SubtractSaturateScalar.Vector64.Int16"] = SubtractSaturateScalar_Vector64_Int16, + ["SubtractSaturateScalar.Vector64.Int32"] = SubtractSaturateScalar_Vector64_Int32, + ["SubtractSaturateScalar.Vector64.SByte"] = SubtractSaturateScalar_Vector64_SByte, + ["SubtractSaturateScalar.Vector64.UInt16"] = SubtractSaturateScalar_Vector64_UInt16, + ["SubtractSaturateScalar.Vector64.UInt32"] = SubtractSaturateScalar_Vector64_UInt32, + ["TransposeEven.Vector64.Byte"] = TransposeEven_Vector64_Byte, + ["TransposeEven.Vector64.Int16"] = TransposeEven_Vector64_Int16, + ["TransposeEven.Vector64.Int32"] = TransposeEven_Vector64_Int32, + ["TransposeEven.Vector64.SByte"] = TransposeEven_Vector64_SByte, + ["TransposeEven.Vector64.Single"] = TransposeEven_Vector64_Single, + ["TransposeEven.Vector64.UInt16"] = TransposeEven_Vector64_UInt16, + ["TransposeEven.Vector64.UInt32"] = TransposeEven_Vector64_UInt32, + ["TransposeEven.Vector128.Byte"] = TransposeEven_Vector128_Byte, + ["TransposeEven.Vector128.Double"] = TransposeEven_Vector128_Double, + ["TransposeEven.Vector128.Int16"] = TransposeEven_Vector128_Int16, + ["TransposeEven.Vector128.Int32"] = TransposeEven_Vector128_Int32, + ["TransposeEven.Vector128.Int64"] = TransposeEven_Vector128_Int64, + ["TransposeEven.Vector128.SByte"] = TransposeEven_Vector128_SByte, + ["TransposeEven.Vector128.Single"] = TransposeEven_Vector128_Single, + ["TransposeEven.Vector128.UInt16"] = TransposeEven_Vector128_UInt16, + ["TransposeEven.Vector128.UInt32"] = TransposeEven_Vector128_UInt32, + ["TransposeEven.Vector128.UInt64"] = TransposeEven_Vector128_UInt64, + ["TransposeOdd.Vector64.Byte"] = TransposeOdd_Vector64_Byte, ["TransposeOdd.Vector64.Int16"] = TransposeOdd_Vector64_Int16, ["TransposeOdd.Vector64.Int32"] = TransposeOdd_Vector64_Int32, ["TransposeOdd.Vector64.SByte"] = TransposeOdd_Vector64_SByte, @@ -65,40 +111,6 @@ static Program() ["UnzipOdd.Vector128.UInt16"] = UnzipOdd_Vector128_UInt16, ["UnzipOdd.Vector128.UInt32"] = UnzipOdd_Vector128_UInt32, ["UnzipOdd.Vector128.UInt64"] = UnzipOdd_Vector128_UInt64, - ["ZipHigh.Vector64.Byte"] = ZipHigh_Vector64_Byte, - ["ZipHigh.Vector64.Int16"] = ZipHigh_Vector64_Int16, - ["ZipHigh.Vector64.Int32"] = ZipHigh_Vector64_Int32, - ["ZipHigh.Vector64.SByte"] = ZipHigh_Vector64_SByte, - ["ZipHigh.Vector64.Single"] = ZipHigh_Vector64_Single, - ["ZipHigh.Vector64.UInt16"] = ZipHigh_Vector64_UInt16, - ["ZipHigh.Vector64.UInt32"] = ZipHigh_Vector64_UInt32, - ["ZipHigh.Vector128.Byte"] = ZipHigh_Vector128_Byte, - ["ZipHigh.Vector128.Double"] = ZipHigh_Vector128_Double, - ["ZipHigh.Vector128.Int16"] = ZipHigh_Vector128_Int16, - ["ZipHigh.Vector128.Int32"] = ZipHigh_Vector128_Int32, - ["ZipHigh.Vector128.Int64"] = ZipHigh_Vector128_Int64, - ["ZipHigh.Vector128.SByte"] = ZipHigh_Vector128_SByte, - ["ZipHigh.Vector128.Single"] = ZipHigh_Vector128_Single, - ["ZipHigh.Vector128.UInt16"] = ZipHigh_Vector128_UInt16, - ["ZipHigh.Vector128.UInt32"] = ZipHigh_Vector128_UInt32, - ["ZipHigh.Vector128.UInt64"] = ZipHigh_Vector128_UInt64, - ["ZipLow.Vector64.Byte"] = ZipLow_Vector64_Byte, - ["ZipLow.Vector64.Int16"] = ZipLow_Vector64_Int16, - ["ZipLow.Vector64.Int32"] = ZipLow_Vector64_Int32, - ["ZipLow.Vector64.SByte"] = ZipLow_Vector64_SByte, - ["ZipLow.Vector64.Single"] = ZipLow_Vector64_Single, - ["ZipLow.Vector64.UInt16"] = ZipLow_Vector64_UInt16, - ["ZipLow.Vector64.UInt32"] = ZipLow_Vector64_UInt32, - ["ZipLow.Vector128.Byte"] = ZipLow_Vector128_Byte, - ["ZipLow.Vector128.Double"] = ZipLow_Vector128_Double, - ["ZipLow.Vector128.Int16"] = ZipLow_Vector128_Int16, - ["ZipLow.Vector128.Int32"] = ZipLow_Vector128_Int32, - ["ZipLow.Vector128.Int64"] = ZipLow_Vector128_Int64, - ["ZipLow.Vector128.SByte"] = ZipLow_Vector128_SByte, - ["ZipLow.Vector128.Single"] = ZipLow_Vector128_Single, - ["ZipLow.Vector128.UInt16"] = ZipLow_Vector128_UInt16, - ["ZipLow.Vector128.UInt32"] = ZipLow_Vector128_UInt32, - ["ZipLow.Vector128.UInt64"] = ZipLow_Vector128_UInt64, }; } } diff --git a/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/Program.AdvSimd.Arm64_Part6.cs b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/Program.AdvSimd.Arm64_Part6.cs new file mode 100644 index 00000000000000..7cf97e14beadc3 --- /dev/null +++ b/src/tests/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/Program.AdvSimd.Arm64_Part6.cs @@ -0,0 +1,51 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + static Program() + { + TestList = new Dictionary() { + ["ZipHigh.Vector64.Byte"] = ZipHigh_Vector64_Byte, + ["ZipHigh.Vector64.Int16"] = ZipHigh_Vector64_Int16, + ["ZipHigh.Vector64.Int32"] = ZipHigh_Vector64_Int32, + ["ZipHigh.Vector64.SByte"] = ZipHigh_Vector64_SByte, + ["ZipHigh.Vector64.Single"] = ZipHigh_Vector64_Single, + ["ZipHigh.Vector64.UInt16"] = ZipHigh_Vector64_UInt16, + ["ZipHigh.Vector64.UInt32"] = ZipHigh_Vector64_UInt32, + ["ZipHigh.Vector128.Byte"] = ZipHigh_Vector128_Byte, + ["ZipHigh.Vector128.Double"] = ZipHigh_Vector128_Double, + ["ZipHigh.Vector128.Int16"] = ZipHigh_Vector128_Int16, + ["ZipHigh.Vector128.Int32"] = ZipHigh_Vector128_Int32, + ["ZipHigh.Vector128.Int64"] = ZipHigh_Vector128_Int64, + ["ZipHigh.Vector128.SByte"] = ZipHigh_Vector128_SByte, + ["ZipHigh.Vector128.Single"] = ZipHigh_Vector128_Single, + ["ZipHigh.Vector128.UInt16"] = ZipHigh_Vector128_UInt16, + ["ZipHigh.Vector128.UInt32"] = ZipHigh_Vector128_UInt32, + ["ZipHigh.Vector128.UInt64"] = ZipHigh_Vector128_UInt64, + ["ZipLow.Vector64.Byte"] = ZipLow_Vector64_Byte, + ["ZipLow.Vector64.Int16"] = ZipLow_Vector64_Int16, + ["ZipLow.Vector64.Int32"] = ZipLow_Vector64_Int32, + ["ZipLow.Vector64.SByte"] = ZipLow_Vector64_SByte, + ["ZipLow.Vector64.Single"] = ZipLow_Vector64_Single, + ["ZipLow.Vector64.UInt16"] = ZipLow_Vector64_UInt16, + ["ZipLow.Vector64.UInt32"] = ZipLow_Vector64_UInt32, + ["ZipLow.Vector128.Byte"] = ZipLow_Vector128_Byte, + ["ZipLow.Vector128.Double"] = ZipLow_Vector128_Double, + ["ZipLow.Vector128.Int16"] = ZipLow_Vector128_Int16, + ["ZipLow.Vector128.Int32"] = ZipLow_Vector128_Int32, + ["ZipLow.Vector128.Int64"] = ZipLow_Vector128_Int64, + ["ZipLow.Vector128.SByte"] = ZipLow_Vector128_SByte, + ["ZipLow.Vector128.Single"] = ZipLow_Vector128_Single, + ["ZipLow.Vector128.UInt16"] = ZipLow_Vector128_UInt16, + ["ZipLow.Vector128.UInt32"] = ZipLow_Vector128_UInt32, + ["ZipLow.Vector128.UInt64"] = ZipLow_Vector128_UInt64, + }; + } + } +} diff --git a/src/tests/JIT/HardwareIntrinsics/Arm/Shared/GenerateTests.csx b/src/tests/JIT/HardwareIntrinsics/Arm/Shared/GenerateTests.csx index e20d87414c251f..c52fa814bc819a 100644 --- a/src/tests/JIT/HardwareIntrinsics/Arm/Shared/GenerateTests.csx +++ b/src/tests/JIT/HardwareIntrinsics/Arm/Shared/GenerateTests.csx @@ -1977,6 +1977,52 @@ private static readonly (string templateFileName, Dictionary tem ("LoadUnOpTest.template", new Dictionary { ["TestName"] = "LoadAndReplicateToVector128_Double", ["Isa"] = "AdvSimd.Arm64", ["Method"] = "LoadAndReplicateToVector128", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(firstOp[0]) != BitConverter.DoubleToInt64Bits(result[i])"}), ("LoadUnOpTest.template", new Dictionary { ["TestName"] = "LoadAndReplicateToVector128_Int64", ["Isa"] = "AdvSimd.Arm64", ["Method"] = "LoadAndReplicateToVector128", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["ValidateIterResult"] = "firstOp[0] != result[i]"}), ("LoadUnOpTest.template", new Dictionary { ["TestName"] = "LoadAndReplicateToVector128_UInt64", ["Isa"] = "AdvSimd.Arm64", ["Method"] = "LoadAndReplicateToVector128", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["ValidateIterResult"] = "firstOp[0] != result[i]"}), + ("LoadPairVectorTest.template", new Dictionary { ["TestName"] = "LoadPairScalarVector64_Int32", ["Isa"] = "AdvSimd.Arm64", ["Method"] = "LoadPairScalarVector64", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.Take(firstOp, 2, i) != Helpers.ConcatScalar(firstResult, secondResult, i)"}), + ("LoadPairVectorTest.template", new Dictionary { ["TestName"] = "LoadPairScalarVector64_Single", ["Isa"] = "AdvSimd.Arm64", ["Method"] = "LoadPairScalarVector64", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.Take(firstOp, 2, i)) != BitConverter.SingleToInt32Bits(Helpers.ConcatScalar(firstResult, secondResult, i))"}), + ("LoadPairVectorTest.template", new Dictionary { ["TestName"] = "LoadPairScalarVector64_UInt32", ["Isa"] = "AdvSimd.Arm64", ["Method"] = "LoadPairScalarVector64", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.Take(firstOp, 2, i) != Helpers.ConcatScalar(firstResult, secondResult, i)"}), + ("LoadPairVectorTest.template", new Dictionary { ["TestName"] = "LoadPairScalarVector64NonTemporal_Int32", ["Isa"] = "AdvSimd.Arm64", ["Method"] = "LoadPairScalarVector64NonTemporal", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.Take(firstOp, 2, i) != Helpers.ConcatScalar(firstResult, secondResult, i)"}), + ("LoadPairVectorTest.template", new Dictionary { ["TestName"] = "LoadPairScalarVector64NonTemporal_Single", ["Isa"] = "AdvSimd.Arm64", ["Method"] = "LoadPairScalarVector64NonTemporal", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.Take(firstOp, 2, i)) != BitConverter.SingleToInt32Bits(Helpers.ConcatScalar(firstResult, secondResult, i))"}), + ("LoadPairVectorTest.template", new Dictionary { ["TestName"] = "LoadPairScalarVector64NonTemporal_UInt32", ["Isa"] = "AdvSimd.Arm64", ["Method"] = "LoadPairScalarVector64NonTemporal", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.Take(firstOp, 2, i) != Helpers.ConcatScalar(firstResult, secondResult, i)"}), + ("LoadPairVectorTest.template", new Dictionary { ["TestName"] = "LoadPairVector64_Byte", ["Isa"] = "AdvSimd.Arm64", ["Method"] = "LoadPairVector64", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "firstOp[i] != Helpers.Concat(firstResult, secondResult, i)"}), + ("LoadPairVectorTest.template", new Dictionary { ["TestName"] = "LoadPairVector64_Double", ["Isa"] = "AdvSimd.Arm64", ["Method"] = "LoadPairVector64", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(firstOp[i]) != BitConverter.DoubleToInt64Bits(Helpers.Concat(firstResult, secondResult, i))"}), + ("LoadPairVectorTest.template", new Dictionary { ["TestName"] = "LoadPairVector64_Int16", ["Isa"] = "AdvSimd.Arm64", ["Method"] = "LoadPairVector64", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "firstOp[i] != Helpers.Concat(firstResult, secondResult, i)"}), + ("LoadPairVectorTest.template", new Dictionary { ["TestName"] = "LoadPairVector64_Int32", ["Isa"] = "AdvSimd.Arm64", ["Method"] = "LoadPairVector64", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "firstOp[i] != Helpers.Concat(firstResult, secondResult, i)"}), + ("LoadPairVectorTest.template", new Dictionary { ["TestName"] = "LoadPairVector64_Int64", ["Isa"] = "AdvSimd.Arm64", ["Method"] = "LoadPairVector64", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["ValidateIterResult"] = "firstOp[i] != Helpers.Concat(firstResult, secondResult, i)"}), + ("LoadPairVectorTest.template", new Dictionary { ["TestName"] = "LoadPairVector64_SByte", ["Isa"] = "AdvSimd.Arm64", ["Method"] = "LoadPairVector64", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "firstOp[i] != Helpers.Concat(firstResult, secondResult, i)"}), + ("LoadPairVectorTest.template", new Dictionary { ["TestName"] = "LoadPairVector64_Single", ["Isa"] = "AdvSimd.Arm64", ["Method"] = "LoadPairVector64", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(firstOp[i]) != BitConverter.SingleToInt32Bits(Helpers.Concat(firstResult, secondResult, i))"}), + ("LoadPairVectorTest.template", new Dictionary { ["TestName"] = "LoadPairVector64_UInt16", ["Isa"] = "AdvSimd.Arm64", ["Method"] = "LoadPairVector64", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "firstOp[i] != Helpers.Concat(firstResult, secondResult, i)"}), + ("LoadPairVectorTest.template", new Dictionary { ["TestName"] = "LoadPairVector64_UInt32", ["Isa"] = "AdvSimd.Arm64", ["Method"] = "LoadPairVector64", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "firstOp[i] != Helpers.Concat(firstResult, secondResult, i)"}), + ("LoadPairVectorTest.template", new Dictionary { ["TestName"] = "LoadPairVector64_UInt64", ["Isa"] = "AdvSimd.Arm64", ["Method"] = "LoadPairVector64", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["ValidateIterResult"] = "firstOp[i] != Helpers.Concat(firstResult, secondResult, i)"}), + ("LoadPairVectorTest.template", new Dictionary { ["TestName"] = "LoadPairVector64NonTemporal_Byte", ["Isa"] = "AdvSimd.Arm64", ["Method"] = "LoadPairVector64NonTemporal", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "firstOp[i] != Helpers.Concat(firstResult, secondResult, i)"}), + ("LoadPairVectorTest.template", new Dictionary { ["TestName"] = "LoadPairVector64NonTemporal_Double", ["Isa"] = "AdvSimd.Arm64", ["Method"] = "LoadPairVector64NonTemporal", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(firstOp[i]) != BitConverter.DoubleToInt64Bits(Helpers.Concat(firstResult, secondResult, i))"}), + ("LoadPairVectorTest.template", new Dictionary { ["TestName"] = "LoadPairVector64NonTemporal_Int16", ["Isa"] = "AdvSimd.Arm64", ["Method"] = "LoadPairVector64NonTemporal", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "firstOp[i] != Helpers.Concat(firstResult, secondResult, i)"}), + ("LoadPairVectorTest.template", new Dictionary { ["TestName"] = "LoadPairVector64NonTemporal_Int32", ["Isa"] = "AdvSimd.Arm64", ["Method"] = "LoadPairVector64NonTemporal", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "firstOp[i] != Helpers.Concat(firstResult, secondResult, i)"}), + ("LoadPairVectorTest.template", new Dictionary { ["TestName"] = "LoadPairVector64NonTemporal_Int64", ["Isa"] = "AdvSimd.Arm64", ["Method"] = "LoadPairVector64NonTemporal", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["ValidateIterResult"] = "firstOp[i] != Helpers.Concat(firstResult, secondResult, i)"}), + ("LoadPairVectorTest.template", new Dictionary { ["TestName"] = "LoadPairVector64NonTemporal_SByte", ["Isa"] = "AdvSimd.Arm64", ["Method"] = "LoadPairVector64NonTemporal", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "firstOp[i] != Helpers.Concat(firstResult, secondResult, i)"}), + ("LoadPairVectorTest.template", new Dictionary { ["TestName"] = "LoadPairVector64NonTemporal_Single", ["Isa"] = "AdvSimd.Arm64", ["Method"] = "LoadPairVector64NonTemporal", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(firstOp[i]) != BitConverter.SingleToInt32Bits(Helpers.Concat(firstResult, secondResult, i))"}), + ("LoadPairVectorTest.template", new Dictionary { ["TestName"] = "LoadPairVector64NonTemporal_UInt16", ["Isa"] = "AdvSimd.Arm64", ["Method"] = "LoadPairVector64NonTemporal", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "firstOp[i] != Helpers.Concat(firstResult, secondResult, i)"}), + ("LoadPairVectorTest.template", new Dictionary { ["TestName"] = "LoadPairVector64NonTemporal_UInt32", ["Isa"] = "AdvSimd.Arm64", ["Method"] = "LoadPairVector64NonTemporal", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "firstOp[i] != Helpers.Concat(firstResult, secondResult, i)"}), + ("LoadPairVectorTest.template", new Dictionary { ["TestName"] = "LoadPairVector64NonTemporal_UInt64", ["Isa"] = "AdvSimd.Arm64", ["Method"] = "LoadPairVector64NonTemporal", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["ValidateIterResult"] = "firstOp[i] != Helpers.Concat(firstResult, secondResult, i)"}), + ("LoadPairVectorTest.template", new Dictionary { ["TestName"] = "LoadPairVector128_Byte", ["Isa"] = "AdvSimd.Arm64", ["Method"] = "LoadPairVector128", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["LargestVectorSize"] = "32", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "firstOp[i] != Helpers.Concat(firstResult, secondResult, i)"}), + ("LoadPairVectorTest.template", new Dictionary { ["TestName"] = "LoadPairVector128_Double", ["Isa"] = "AdvSimd.Arm64", ["Method"] = "LoadPairVector128", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["LargestVectorSize"] = "32", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(firstOp[i]) != BitConverter.DoubleToInt64Bits(Helpers.Concat(firstResult, secondResult, i))"}), + ("LoadPairVectorTest.template", new Dictionary { ["TestName"] = "LoadPairVector128_Int16", ["Isa"] = "AdvSimd.Arm64", ["Method"] = "LoadPairVector128", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["LargestVectorSize"] = "32", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "firstOp[i] != Helpers.Concat(firstResult, secondResult, i)"}), + ("LoadPairVectorTest.template", new Dictionary { ["TestName"] = "LoadPairVector128_Int32", ["Isa"] = "AdvSimd.Arm64", ["Method"] = "LoadPairVector128", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["LargestVectorSize"] = "32", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "firstOp[i] != Helpers.Concat(firstResult, secondResult, i)"}), + ("LoadPairVectorTest.template", new Dictionary { ["TestName"] = "LoadPairVector128_Int64", ["Isa"] = "AdvSimd.Arm64", ["Method"] = "LoadPairVector128", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int64", ["LargestVectorSize"] = "32", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["ValidateIterResult"] = "firstOp[i] != Helpers.Concat(firstResult, secondResult, i)"}), + ("LoadPairVectorTest.template", new Dictionary { ["TestName"] = "LoadPairVector128_SByte", ["Isa"] = "AdvSimd.Arm64", ["Method"] = "LoadPairVector128", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["LargestVectorSize"] = "32", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "firstOp[i] != Helpers.Concat(firstResult, secondResult, i)"}), + ("LoadPairVectorTest.template", new Dictionary { ["TestName"] = "LoadPairVector128_Single", ["Isa"] = "AdvSimd.Arm64", ["Method"] = "LoadPairVector128", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["LargestVectorSize"] = "32", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(firstOp[i]) != BitConverter.SingleToInt32Bits(Helpers.Concat(firstResult, secondResult, i))"}), + ("LoadPairVectorTest.template", new Dictionary { ["TestName"] = "LoadPairVector128_UInt16", ["Isa"] = "AdvSimd.Arm64", ["Method"] = "LoadPairVector128", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["LargestVectorSize"] = "32", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "firstOp[i] != Helpers.Concat(firstResult, secondResult, i)"}), + ("LoadPairVectorTest.template", new Dictionary { ["TestName"] = "LoadPairVector128_UInt32", ["Isa"] = "AdvSimd.Arm64", ["Method"] = "LoadPairVector128", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["LargestVectorSize"] = "32", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "firstOp[i] != Helpers.Concat(firstResult, secondResult, i)"}), + ("LoadPairVectorTest.template", new Dictionary { ["TestName"] = "LoadPairVector128_UInt64", ["Isa"] = "AdvSimd.Arm64", ["Method"] = "LoadPairVector128", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt64", ["LargestVectorSize"] = "32", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["ValidateIterResult"] = "firstOp[i] != Helpers.Concat(firstResult, secondResult, i)"}), + ("LoadPairVectorTest.template", new Dictionary { ["TestName"] = "LoadPairVector128NonTemporal_Byte", ["Isa"] = "AdvSimd.Arm64", ["Method"] = "LoadPairVector128NonTemporal", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["LargestVectorSize"] = "32", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "firstOp[i] != Helpers.Concat(firstResult, secondResult, i)"}), + ("LoadPairVectorTest.template", new Dictionary { ["TestName"] = "LoadPairVector128NonTemporal_Double", ["Isa"] = "AdvSimd.Arm64", ["Method"] = "LoadPairVector128NonTemporal", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["LargestVectorSize"] = "32", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(firstOp[i]) != BitConverter.DoubleToInt64Bits(Helpers.Concat(firstResult, secondResult, i))"}), + ("LoadPairVectorTest.template", new Dictionary { ["TestName"] = "LoadPairVector128NonTemporal_Int16", ["Isa"] = "AdvSimd.Arm64", ["Method"] = "LoadPairVector128NonTemporal", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["LargestVectorSize"] = "32", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "firstOp[i] != Helpers.Concat(firstResult, secondResult, i)"}), + ("LoadPairVectorTest.template", new Dictionary { ["TestName"] = "LoadPairVector128NonTemporal_Int32", ["Isa"] = "AdvSimd.Arm64", ["Method"] = "LoadPairVector128NonTemporal", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["LargestVectorSize"] = "32", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "firstOp[i] != Helpers.Concat(firstResult, secondResult, i)"}), + ("LoadPairVectorTest.template", new Dictionary { ["TestName"] = "LoadPairVector128NonTemporal_Int64", ["Isa"] = "AdvSimd.Arm64", ["Method"] = "LoadPairVector128NonTemporal", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int64", ["LargestVectorSize"] = "32", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["ValidateIterResult"] = "firstOp[i] != Helpers.Concat(firstResult, secondResult, i)"}), + ("LoadPairVectorTest.template", new Dictionary { ["TestName"] = "LoadPairVector128NonTemporal_SByte", ["Isa"] = "AdvSimd.Arm64", ["Method"] = "LoadPairVector128NonTemporal", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["LargestVectorSize"] = "32", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "firstOp[i] != Helpers.Concat(firstResult, secondResult, i)"}), + ("LoadPairVectorTest.template", new Dictionary { ["TestName"] = "LoadPairVector128NonTemporal_Single", ["Isa"] = "AdvSimd.Arm64", ["Method"] = "LoadPairVector128NonTemporal", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["LargestVectorSize"] = "32", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(firstOp[i]) != BitConverter.SingleToInt32Bits(Helpers.Concat(firstResult, secondResult, i))"}), + ("LoadPairVectorTest.template", new Dictionary { ["TestName"] = "LoadPairVector128NonTemporal_UInt16", ["Isa"] = "AdvSimd.Arm64", ["Method"] = "LoadPairVector128NonTemporal", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["LargestVectorSize"] = "32", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "firstOp[i] != Helpers.Concat(firstResult, secondResult, i)"}), + ("LoadPairVectorTest.template", new Dictionary { ["TestName"] = "LoadPairVector128NonTemporal_UInt32", ["Isa"] = "AdvSimd.Arm64", ["Method"] = "LoadPairVector128NonTemporal", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["LargestVectorSize"] = "32", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "firstOp[i] != Helpers.Concat(firstResult, secondResult, i)"}), + ("LoadPairVectorTest.template", new Dictionary { ["TestName"] = "LoadPairVector128NonTemporal_UInt64", ["Isa"] = "AdvSimd.Arm64", ["Method"] = "LoadPairVector128NonTemporal", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt64", ["LargestVectorSize"] = "32", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["ValidateIterResult"] = "firstOp[i] != Helpers.Concat(firstResult, secondResult, i)"}), ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Max_Vector128_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "Max", ["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.Max(left[i], right[i])) != BitConverter.DoubleToInt64Bits(result[i])"}), ("VecReduceUnOpTest.template", new Dictionary { ["TestName"] = "MaxAcross_Vector64_Byte", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MaxAcross", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["ValidateReduceOpResult"] = "Helpers.MaxAcross(firstOp) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), ("VecReduceUnOpTest.template", new Dictionary { ["TestName"] = "MaxAcross_Vector64_Int16", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MaxAcross", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["ValidateReduceOpResult"] = "Helpers.MaxAcross(firstOp) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), diff --git a/src/tests/JIT/HardwareIntrinsics/Arm/Shared/Helpers.cs b/src/tests/JIT/HardwareIntrinsics/Arm/Shared/Helpers.cs index ba1e776bdba00c..40a2075d7dea62 100644 --- a/src/tests/JIT/HardwareIntrinsics/Arm/Shared/Helpers.cs +++ b/src/tests/JIT/HardwareIntrinsics/Arm/Shared/Helpers.cs @@ -5319,6 +5319,8 @@ public static sbyte ConcatScalar(sbyte[] op1, sbyte[] op2, int i) public static sbyte Insert(sbyte[] op1, int op2, sbyte op3, int i) => (op2 != i) ? op1[i] : op3; + public static sbyte Take(sbyte[] op1, int count, int i) => (i < count) ? op1[i] : 0; + public static byte Concat(byte[] op1, byte[] op2, int i) => (i < op1.Length) ? op1[i] : op2[i - op1.Length]; public static byte ConcatScalar(byte[] op1, byte[] op2, int i) @@ -5335,6 +5337,8 @@ public static byte ConcatScalar(byte[] op1, byte[] op2, int i) public static byte Insert(byte[] op1, int op2, byte op3, int i) => (op2 != i) ? op1[i] : op3; + public static byte Take(byte[] op1, int count, int i) => (i < count) ? op1[i] : 0; + public static short Concat(short[] op1, short[] op2, int i) => (i < op1.Length) ? op1[i] : op2[i - op1.Length]; public static short ConcatScalar(short[] op1, short[] op2, int i) @@ -5351,6 +5355,8 @@ public static short ConcatScalar(short[] op1, short[] op2, int i) public static short Insert(short[] op1, int op2, short op3, int i) => (op2 != i) ? op1[i] : op3; + public static short Take(short[] op1, int count, int i) => (i < count) ? op1[i] : 0; + public static ushort Concat(ushort[] op1, ushort[] op2, int i) => (i < op1.Length) ? op1[i] : op2[i - op1.Length]; public static ushort ConcatScalar(ushort[] op1, ushort[] op2, int i) @@ -5367,6 +5373,8 @@ public static ushort ConcatScalar(ushort[] op1, ushort[] op2, int i) public static ushort Insert(ushort[] op1, int op2, ushort op3, int i) => (op2 != i) ? op1[i] : op3; + public static ushort Take(ushort[] op1, int count, int i) => (i < count) ? op1[i] : 0; + public static int Concat(int[] op1, int[] op2, int i) => (i < op1.Length) ? op1[i] : op2[i - op1.Length]; public static int ConcatScalar(int[] op1, int[] op2, int i) @@ -5383,6 +5391,8 @@ public static int ConcatScalar(int[] op1, int[] op2, int i) public static int Insert(int[] op1, int op2, int op3, int i) => (op2 != i) ? op1[i] : op3; + public static int Take(int[] op1, int count, int i) => (i < count) ? op1[i] : 0; + public static uint Concat(uint[] op1, uint[] op2, int i) => (i < op1.Length) ? op1[i] : op2[i - op1.Length]; public static uint ConcatScalar(uint[] op1, uint[] op2, int i) @@ -5399,6 +5409,8 @@ public static uint ConcatScalar(uint[] op1, uint[] op2, int i) public static uint Insert(uint[] op1, int op2, uint op3, int i) => (op2 != i) ? op1[i] : op3; + public static uint Take(uint[] op1, int count, int i) => (i < count) ? op1[i] : 0; + public static long Concat(long[] op1, long[] op2, int i) => (i < op1.Length) ? op1[i] : op2[i - op1.Length]; public static long ConcatScalar(long[] op1, long[] op2, int i) @@ -5415,6 +5427,8 @@ public static long ConcatScalar(long[] op1, long[] op2, int i) public static long Insert(long[] op1, int op2, long op3, int i) => (op2 != i) ? op1[i] : op3; + public static long Take(long[] op1, int count, int i) => (i < count) ? op1[i] : 0; + public static ulong Concat(ulong[] op1, ulong[] op2, int i) => (i < op1.Length) ? op1[i] : op2[i - op1.Length]; public static ulong ConcatScalar(ulong[] op1, ulong[] op2, int i) @@ -5431,6 +5445,8 @@ public static ulong ConcatScalar(ulong[] op1, ulong[] op2, int i) public static ulong Insert(ulong[] op1, int op2, ulong op3, int i) => (op2 != i) ? op1[i] : op3; + public static ulong Take(ulong[] op1, int count, int i) => (i < count) ? op1[i] : 0; + public static float Concat(float[] op1, float[] op2, int i) => (i < op1.Length) ? op1[i] : op2[i - op1.Length]; public static float ConcatScalar(float[] op1, float[] op2, int i) @@ -5447,6 +5463,8 @@ public static float ConcatScalar(float[] op1, float[] op2, int i) public static float Insert(float[] op1, int op2, float op3, int i) => (op2 != i) ? op1[i] : op3; + public static float Take(float[] op1, int count, int i) => (i < count) ? op1[i] : 0; + public static double Concat(double[] op1, double[] op2, int i) => (i < op1.Length) ? op1[i] : op2[i - op1.Length]; public static double ConcatScalar(double[] op1, double[] op2, int i) @@ -5463,6 +5481,8 @@ public static double ConcatScalar(double[] op1, double[] op2, int i) public static double Insert(double[] op1, int op2, double op3, int i) => (op2 != i) ? op1[i] : op3; + public static double Take(double[] op1, int count, int i) => (i < count) ? op1[i] : 0; + public static sbyte TableVectorExtension(int i, sbyte[] defaultValues, sbyte[] indices, params sbyte[][] table) { sbyte[] fullTable = table.SelectMany(x => x).ToArray(); diff --git a/src/tests/JIT/HardwareIntrinsics/Arm/Shared/Helpers.tt b/src/tests/JIT/HardwareIntrinsics/Arm/Shared/Helpers.tt index 5e472b09d7c035..42a6868957a152 100644 --- a/src/tests/JIT/HardwareIntrinsics/Arm/Shared/Helpers.tt +++ b/src/tests/JIT/HardwareIntrinsics/Arm/Shared/Helpers.tt @@ -1435,6 +1435,8 @@ namespace JIT.HardwareIntrinsics.Arm public static <#= typeName #> Insert(<#= typeName #>[] op1, int op2, <#= typeName #> op3, int i) => (op2 != i) ? op1[i] : op3; + public static <#= typeName #> Take(<#= typeName #>[] op1, int count, int i) => (i < count) ? op1[i] : 0; + <# } diff --git a/src/tests/JIT/HardwareIntrinsics/Arm/Shared/LoadPairVectorTest.template b/src/tests/JIT/HardwareIntrinsics/Arm/Shared/LoadPairVectorTest.template new file mode 100644 index 00000000000000..8512a2b96255ee --- /dev/null +++ b/src/tests/JIT/HardwareIntrinsics/Arm/Shared/LoadPairVectorTest.template @@ -0,0 +1,203 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Reflection; +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 {TestName}() + { + var test = new {TestName}(); + + if (test.IsSupported) + { + // Validates basic functionality works + test.RunBasicScenario_Load(); + + // Validates calling via reflection works + test.RunReflectionScenario_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 {TestName} + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray1; + private byte[] outArray2; + + private GCHandle inHandle1; + private GCHandle outHandle1; + private GCHandle outHandle2; + + private ulong alignment; + + public DataTable({Op1BaseType}[] inArray1, {RetBaseType}[] outArray1, {RetBaseType}[] outArray2, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf<{Op1BaseType}>(); + int sizeOfoutArray1 = outArray1.Length * Unsafe.SizeOf<{RetBaseType}>(); + int sizeOfoutArray2 = outArray2.Length * Unsafe.SizeOf<{RetBaseType}>(); + if ((alignment != 16 && alignment != 32) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray1 || (alignment * 2) < sizeOfoutArray2) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray1 = new byte[alignment * 2]; + this.outArray2 = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle1 = GCHandle.Alloc(this.outArray1, GCHandleType.Pinned); + this.outHandle2 = GCHandle.Alloc(this.outArray2, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As<{Op1BaseType}, byte>(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArray1Ptr => Align((byte*)(outHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArray2Ptr => Align((byte*)(outHandle2.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle1.Free(); + outHandle2.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private static readonly int LargestVectorSize = {LargestVectorSize}; + + private static readonly int Ret1ElementCount = Unsafe.SizeOf<{RetVectorType}<{RetBaseType}>>() / sizeof({RetBaseType}); + private static readonly int Ret2ElementCount = Unsafe.SizeOf<{RetVectorType}<{RetBaseType}>>() / sizeof({RetBaseType}); + private static readonly int Op1ElementCount = Ret1ElementCount + Ret2ElementCount; + + private static {Op1BaseType}[] _data = new {Op1BaseType}[Op1ElementCount]; + + private DataTable _dataTable; + + public {TestName}() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = {NextValueOp1}; } + _dataTable = new DataTable(_data, new {RetBaseType}[Ret1ElementCount], new {RetBaseType}[Ret2ElementCount], LargestVectorSize); + } + + public bool IsSupported => {Isa}.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var (value1, value2) = {Isa}.{Method}(({Op1BaseType}*)(_dataTable.inArray1Ptr)); + Unsafe.Write(_dataTable.outArray1Ptr, value1); + Unsafe.Write(_dataTable.outArray2Ptr, value2); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArray1Ptr, _dataTable.outArray2Ptr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof({Isa}).GetMethod(nameof({Isa}.{Method}), new Type[] { typeof({Op1BaseType}*) }) + .Invoke(null, new object[] { + Pointer.Box(_dataTable.inArray1Ptr, typeof({Op1BaseType}*)) + }); + + var (value1, value2) = (({RetVectorType}<{RetBaseType}>, {RetVectorType}<{RetBaseType}>))result; + + Unsafe.Write(_dataTable.outArray1Ptr, value1); + Unsafe.Write(_dataTable.outArray2Ptr, value2); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArray1Ptr, _dataTable.outArray2Ptr); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + Succeeded = false; + + try + { + RunBasicScenario_Load(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(void* firstOp, void* result1, void* result2, [CallerMemberName] string method = "") + { + {Op1BaseType}[] inArray = new {Op1BaseType}[Op1ElementCount]; + {RetBaseType}[] outArray1 = new {RetBaseType}[Ret1ElementCount]; + {RetBaseType}[] outArray2 = new {RetBaseType}[Ret2ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{Op1BaseType}, byte>(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)(Unsafe.SizeOf<{RetBaseType}>() * Op1ElementCount)); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{RetBaseType}, byte>(ref outArray1[0]), ref Unsafe.AsRef(result1), (uint)Unsafe.SizeOf<{RetVectorType}<{RetBaseType}>>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{RetBaseType}, byte>(ref outArray2[0]), ref Unsafe.AsRef(result2), (uint)Unsafe.SizeOf<{RetVectorType}<{RetBaseType}>>()); + + ValidateResult(inArray, outArray1, outArray2, method); + } + + private void ValidateResult({Op1BaseType}[] firstOp, {RetBaseType}[] firstResult, {RetBaseType}[] secondResult, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (int i = 0; i < Op1ElementCount; i++) + { + if ({ValidateIterResult}) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof({Isa})}.{nameof({Isa}.{Method})}<{RetBaseType}>({Op1VectorType}<{Op1BaseType}>): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" firstResult: ({string.Join(", ", firstResult)})"); + TestLibrary.TestFramework.LogInformation($"secondResult: ({string.Join(", ", secondResult)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_11782/Runtime_11782.cs b/src/tests/JIT/Regression/JitBlue/Runtime_11782/Runtime_11782.cs new file mode 100644 index 00000000000000..657553577b6db7 --- /dev/null +++ b/src/tests/JIT/Regression/JitBlue/Runtime_11782/Runtime_11782.cs @@ -0,0 +1,53 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Runtime.Intrinsics.X86; +using System.Runtime.CompilerServices; + +namespace Runtime_11782 +{ + + class Program + { + [MethodImpl(MethodImplOptions.NoInlining)] + static unsafe uint mulx(uint a, uint b) + { + uint r; + return Bmi2.MultiplyNoFlags(a, b, &r) + r; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static unsafe ulong mulx_64(ulong a, ulong b) + { + ulong r; + return Bmi2.X64.MultiplyNoFlags(a, b, &r) + r; + } + + static int Main() + { + int returnVal = 100; + + if (Bmi2.IsSupported) + { + uint u1 = mulx(0xf0000000, 0x10); + if (u1 != 0xf) + { + Console.WriteLine("32-bit mulx failed: u1 = 0x{0:X}", u1 ); + returnVal = -1; + } + if (Bmi2.X64.IsSupported) + { + ulong ul1 = mulx_64(0xf00000000, 0x10); + if (ul1 != 0xf000000000UL) + { + Console.WriteLine("64-bit mulx failed: ul1 = 0x{0:X}", ul1); + returnVal = -1; + } + } + } + return returnVal; + } + } +} diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_11782/Runtime_11782.csproj b/src/tests/JIT/Regression/JitBlue/Runtime_11782/Runtime_11782.csproj new file mode 100644 index 00000000000000..5d49e8d49736fa --- /dev/null +++ b/src/tests/JIT/Regression/JitBlue/Runtime_11782/Runtime_11782.csproj @@ -0,0 +1,13 @@ + + + Exe + + + + True + True + + + + +